Hi --

On Sun, 14 Aug 2005, gabriele renzi wrote:

> David A. Black ha scritto:
>> Hi --
>> 
>> On Sun, 14 Aug 2005, gabriele renzi wrote:
>> 
>>> Hi gurus and nubys,
>>> 
>>> is there a way to add a constant into an object which is not a 
>>> module/class?
>>> 
>>> Basically what I'd like is some kind of append_features/include that works 
>>> on non-module objects.
>>> 
>>> Is my only chance to mess up with the singleton class by myself, or there 
>>> is some existing method for this?
>> 
>> 
>> If I understand you correctly, I think Kernel#extend is what you need:
>> 
>>   irb(main):001:0> s = ""
>>   => ""
>>   irb(main):002:0> module M; X=1; end
>>   => 1
>>   irb(main):003:0> s.extend(M)
>>   => ""
>>   irb(main):004:0> (class << s; self; end)::X
>>   => 1
>> 
>> I think that's the closest thing corresponding to "adding a constant"
>> to an arbitrary object (adding it to the object's singleton class).
>
> well, ri explicitly says for #extend:
> " Adds to _obj_ the instance methods from each module given as a
> parameter"
> and this is omitting Constants, which are available when something is 
> #include'd

I'm not sure what you mean by "adding a constant to an object" if the
object isn't a Class or Module.  For example:

   obj = Object.new
   obj.constants    => no such method

All constants live in a class/module namespace.  That's what I mean
when I say the closest you can get is adding it to an object's
singleton class.

> See example:
>
> I won't be able to access singleton class constants from the singleton 
> instance, it seems:
>
>>> class Foo
>>>  def barer
>>>   Bar.new
>>>  end
>>> end
> => nil
>>> module M
>>>  class Bar
>>>  end
>>> end
> => nil
>>> foo=Foo.new
> => #<Foo:0x2d01428>
>>> foo.extend M
> => #<Foo:0x2d01428>
>>> foo.barer   # I'd like to get a Bar instance here
> NameError: uninitialized constant Foo2::Bar

Where did "Foo2" come from?  I get Foo::Bar :-)

>        from (irb):12:in `barer'
>        from (irb):21
>
> I don't understand why, actually.

I think it's this:  when an instance method refers to a constant, that
constant is looked up in the class where the method is defined.
Therefore, in your example, Foo#barer looks for Foo::Bar.

So it's not the same as a method call, where it would be looked up in
the object's singleton class.  I guess that's because constants really
belong to classes, not to objects generally.  So when you ask for a
constant, the class you're in doesn't branch off and look in other
classes.

This may have to do with the way constant references are parsed, which
is kind of quasi-static.

Anyway, here's an illustration.

class Foo
  def x
    p X
  end
end

foo = Foo.new

class << foo
   X = 1
   Y = 1
   def y
     p Y
   end
end

foo.y         => 1  (that's <foo's singleton class>::Y)
foo.x         => uninitialized constant Foo::X
                     (foo's singleton class isn't involved)


David

-- 
David A. Black
dblack / wobblini.net