From: Joshua Ballanco Date: 2011-10-04T10:50:11+09:00 Subject: [ruby-core:39907] Re: Modules as library forms --4e8a664f_379a5b56_4992 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Content-Disposition: inline On Monday, October 3, 2011 at 9:00 AM, Gary Wright wrote: > It isn't clear to me how this solves the scoping problem. Consider: > > class Foo > String = String.except(A) > > s = "a string literal" > s.some_method_from_module_A # NoMethodError ?? > end > > How exactly is Ruby going to determine that the literal should be an instance of Foo::String rather than ::String? What if I call File.read within the class block? Will the returned string be a Foo::String? If so, how is File.read supposed to implement that? So, to answer your first point, string literals would still be instances of the top-level string class. If you wanted a string without A mixed in, you would do: class Foo String = String.except(A) s = String.new("a string literal") end As for the second question, File.read would still return a ::String. Actually, I removed a final paragraph from my original proposal because I thought it might be a bit too confusing, but in this case I think it would actually make things clearer. In addition to Module#only, Module#except, Module#prefix, and Module#rename, I would also propose Binding#import which would allow one to inject a library form (Class/Module) into the binding of another library form, returning a new library form (essentially cloning the class and binding and dynamically injecting a new binding). This way, if you wanted File.read to return a String with module A excluded, you would do: class Foo myString = String.except(A) myFile = File.send(:binding).import(myString) #=> myFile will now create Strings excluding module A upon String.new def bar s = myFile.read('/path/to/file') s.some_method_from_module_A #=> NoMethodError end end (Note that in this example I used myString and myFile to make the modifications clear, but assigning to String and File should have the same effect.) The biggest issue I can foresee with this proposal is that cloning a binding might get very costly. I think that in order for this part of my proposal to work, we would need to re-think the openness of bindings in Ruby (something that I have actively advocated for anyhow). I should also say that to keep the code cleaner, I think I would actually prefer a Module#import instead of requiring the programmer to manually extract the binding and inject the new form, but the same underlying manipulations of module/class bindings would need to occur regardless. Thanks for the feedback! - Josh --4e8a664f_379a5b56_4992 Content-Type: text/html; charset="utf-8" Content-Transfer-Encoding: quoted-printable Content-Disposition: inline
On Monday, October 3, 2011 at 9:00 AM, Gary Wr= ight wrote:
It isn't c= lear to me how this solves the scoping problem.  Consider:

class =46oo
  String =3D String.= except(A)
  
  s =3D =22a string liter= al=22
  s.some=5Fmethod=5Ffrom=5Fmodule=5FA   =23 NoMethod= Error =3F=3F
end

How exactly is Ruby going t= o determine that the literal should be an instance of =46oo::String rathe= r than ::String=3F  What if I call =46ile.read within the class bloc= k=3F  Will the returned string be a =46oo::String=3F  If so, ho= w is =46ile.read supposed to implement that=3F
 
=20
So, to answer your first point, string literals would= still be instances of the top-level string class. If you wanted a string= without A mixed in, you would do:

    class =46oo
=
      String =3D String.except(A)
  &n= bsp;   
      s =3D String.new(=22a st= ring literal=22)
    end

As = for the second question, =46ile.read would still return a ::String.
=

Actually, I removed a final paragraph from my origina= l proposal because I thought it might be a bit too confusing, but in this= case I think it would actually make things clearer. In addition to Modul= e=23only, Module=23except, Module=23prefix, and Module=23rename, I would = also propose Binding=23import which would allow one to inject a library f= orm (Class/Module) into the binding of another library form, returning a = new library form (essentially cloning the class and binding and dynamical= ly injecting a new binding). This way, if you wanted =46ile.read to retur= n a String with module A excluded, you would do:

    class =46oo
      myString =3D St= ring.except(A)
      my=46ile =3D =46ile.send(:b= inding).import(myString)
      =23=3D> my=46i= le will now create Strings excluding module A upon String.new
&= nbsp;     def bar
        s =3D m= y=46ile.read('/path/to/file')
        s.som= e=5Fmethod=5Ffrom=5Fmodule=5FA =23=3D> NoMethodError
  =     end
    end

(N= ote that in this example I used myString and my=46ile to make the modific= ations clear, but assigning to String and =46ile should have the same eff= ect.) The biggest issue I can foresee with this proposal is that cloning = a binding might get very costly. I think that in order for this part of m= y proposal to work, we would need to re-think the openness of bindings in= Ruby (something that I have actively advocated for anyhow).
I should also say that to keep the code cleaner, I think I w= ould actually prefer a Module=23import instead of requiring the programme= r to manually extract the binding and inject the new form, but the same u= nderlying manipulations of module/class bindings would need to occur rega= rdless.

Thanks for the feedback=21
- Josh
--4e8a664f_379a5b56_4992--