[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

"instance_eval" (eg, sent to a class object

Greg Weeks

11/16/2007 9:07:00 PM

I've poked around, but I don't get instance_eval at all.

I do know what it means to evaluate code in the context of a *class*
object. Ie, I know what *this* does:

class Foo
# We're now in the context of the object Foo.
C = 1
class Bar
def bar ; "bar" ; end
end
def foo ; "foo" ; end
end
p Foo::C -> 1
p Foo::Bar.new.bar -> "bar"
p Foo.new.foo -> "foo"

Now let's try this again with "instance_eval":

class Foo
end
Foo.instance_eval do
# We're now supposedly in the context of the object Foo.
C = 1
class Bar
def bar ; "bar" ; end
end
def foo ; "foo" ; end
end
p Foo::C
p Foo::Bar.new.bar
p Foo.new.foo

Nothing works as I expected. The result is:

tmp.rb:26: warning: toplevel constant C referenced by Foo::C
1
tmp.rb:27: warning: toplevel constant Bar referenced by Foo::Bar
"bar"
tmp.rb:28: undefined method `foo' for #<Foo:0x401c25b0> (NoMethodError)

Evidentally, C and Bar scoped lexically, rather than being in the
context of Foo. And the foo definition ended up in the context of
"class <<Foo ... end".

So, hat in hand, I ask for a description of "instance_eval".
--
Posted via http://www.ruby-....

10 Answers

David A. Black

11/16/2007 9:53:00 PM

0

Hi --

On Sat, 17 Nov 2007, Greg Weeks wrote:

> I've poked around, but I don't get instance_eval at all.
>
> I do know what it means to evaluate code in the context of a *class*
> object. Ie, I know what *this* does:
>
> class Foo
> # We're now in the context of the object Foo.
> C = 1
> class Bar
> def bar ; "bar" ; end
> end
> def foo ; "foo" ; end
> end
> p Foo::C -> 1
> p Foo::Bar.new.bar -> "bar"
> p Foo.new.foo -> "foo"
>
> Now let's try this again with "instance_eval":
>
> class Foo
> end
> Foo.instance_eval do
> # We're now supposedly in the context of the object Foo.
> C = 1
> class Bar
> def bar ; "bar" ; end
> end
> def foo ; "foo" ; end
> end
> p Foo::C
> p Foo::Bar.new.bar
> p Foo.new.foo
>
> Nothing works as I expected. The result is:
>
> tmp.rb:26: warning: toplevel constant C referenced by Foo::C
> 1
> tmp.rb:27: warning: toplevel constant Bar referenced by Foo::Bar
> "bar"
> tmp.rb:28: undefined method `foo' for #<Foo:0x401c25b0> (NoMethodError)
>
> Evidentally, C and Bar scoped lexically, rather than being in the
> context of Foo. And the foo definition ended up in the context of
> "class <<Foo ... end".
>
> So, hat in hand, I ask for a description of "instance_eval".

It changes 'self' to the receiver, for the duration of the block.
That's pretty much all it does. So here:

class A
end

"hello".instance_eval { class B; end }

class B doesn't care that some string has become self; it still
considers itself a top-level class definition.


David

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
* Advancing With Rails, Berlin, Germany, November 19-22
* Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.r... for details!

Rick DeNatale

11/16/2007 10:01:00 PM

0

On Nov 16, 2007 4:06 PM, Greg Weeks <greg.weeks@arm.com> wrote:
> I've poked around, but I don't get instance_eval at all.
>
> I do know what it means to evaluate code in the context of a *class*
> object. Ie, I know what *this* does:
>
> class Foo
> # We're now in the context of the object Foo.
> C = 1
> class Bar
> def bar ; "bar" ; end
> end
> def foo ; "foo" ; end
> end
> p Foo::C -> 1
> p Foo::Bar.new.bar -> "bar"
> p Foo.new.foo -> "foo"
>
> Now let's try this again with "instance_eval":
>
> class Foo
> end
> Foo.instance_eval do
> # We're now supposedly in the context of the object Foo.
> C = 1
> class Bar
> def bar ; "bar" ; end
> end
> def foo ; "foo" ; end
> end
> p Foo::C
> p Foo::Bar.new.bar
> p Foo.new.foo
>
> Nothing works as I expected. The result is:
>
> tmp.rb:26: warning: toplevel constant C referenced by Foo::C
> 1
> tmp.rb:27: warning: toplevel constant Bar referenced by Foo::Bar
> "bar"
> tmp.rb:28: undefined method `foo' for #<Foo:0x401c25b0> (NoMethodError)
>
> Evidentally, C and Bar scoped lexically, rather than being in the
> context of Foo. And the foo definition ended up in the context of
> "class <<Foo ... end".
>
> So, hat in hand, I ask for a description of "instance_eval".

It only affects the execution context by binding self to the instance,
NOT the lexical context.



--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Greg Weeks

11/16/2007 10:59:00 PM

0

> It changes 'self' to the receiver, for the duration of the block.

> It only affects the execution context by binding self to the instance

And the value of self affects:

- explicit uses of "self"
- naked message-sends
- instance and class variable access

Anything else?

Hmmm. This is still a mystery:

class Foo
end
Foo.instance_eval do
def foo ; "foo" ; end
end
p Foo.singleton_methods -> ["foo"]

The "def" should have gone into the top-level environment, but it went
into <<Foo instead. So my hat is still out. (But I'm a lot better off
than I was.)
--
Posted via http://www.ruby-....

Rick DeNatale

11/17/2007 12:20:00 AM

0

On Nov 16, 2007 5:59 PM, Greg Weeks <greg.weeks@arm.com> wrote:
> > It changes 'self' to the receiver, for the duration of the block.
>
> > It only affects the execution context by binding self to the instance
>
> And the value of self affects:
>
> - explicit uses of "self"
> - naked message-sends
> - instance and class variable access
>
> Anything else?
>
> Hmmm. This is still a mystery:
>
> class Foo
> end
> Foo.instance_eval do
> def foo ; "foo" ; end
> end
> p Foo.singleton_methods -> ["foo"]
>
> The "def" should have gone into the top-level environment, but it went
> into <<Foo instead. So my hat is still out. (But I'm a lot better off
> than I was.)

Consider

# At the top level self is a specific top-level object

def foo
# This method will be a singleton method of the top-level object
# It's installed in the method-hash of the singleton-class of the
top level object.
end

# when methods are required in reponse to a send, a search is
instituted starting with the receivers klass (i.e. it's true class
which may
# be a singleton class which is put on the search chain ahead of the
objects 'birth' class.
# Classes, including singleton classes, have a method hash which maps
method names to methods.
# For purposes of this post, I'm going to say that classes contain the
methods of their instances via this method hash.

Foo.instance_eval do
# self is now the class object named Foo
def foo2
# This method will be a singleton method of Foo
# it gets installed in the method-hash of the singleton-class of Foo
end
end

Now the fact that foo2 is a singleton method is a side-effect of
sorts. It's really a class method of Foo.

It get's reported as a singleton class because it's 'contained' in a
singleton class. This is true of normal class methods for example:

Array.singleton_methods => ["[]"]
Array.methods(false) => ["[]"]


Now all this begged a question in my mind. That is, what's the
difference between instance_eval and class_eval (with its alias
module_eval). A little digging in the 1.8.6 MRI code reveals that
both use the same underlying code, but the inner c function
specific_eval (in eval.c) takes both a klass and a self argument.

Both rb_object_instance_eval (the code behind Kernel#instance_eval)
and rb_mod_module_eval (the code behind both Module#module_eval and
Module#class_eval) set the self argument to the receiver.

rb_obj_instance_eval sets the klass argument to the singleton_class of
the receiver (creating it if it doesn't already exist), unless the
receiver is an immediate object (a Fixnum, or nil, true, or false) in
which case it sets klass to nil.

rb_mod_module_eval sets the klass argument to the receiver which must
be a module or a class. It's the klass argument of specific_eval
which ultimately determines the destination of a method defined by
def;end in the block.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denh...

Greg Weeks

11/17/2007 12:33:00 AM

0

Rick Denatale wrote:
> def foo
> # This method will be a singleton method of the top-level object
> # It's installed in the method-hash of the singleton-class of the
> top level object.
> end

But this is not true (because of top-level magic, about which I just
posted a lament). The method foo is installed as if in "class Object
... end":

def foo ; "foo" ; end
self.singleton_methods.include? "foo" -> false
Object.methods.include? "foo" -> true (in irb)

(All of which contributes to my confusion about "instance_eval", alas.)
--
Posted via http://www.ruby-....

Greg Weeks

11/17/2007 12:52:00 AM

0

Setting aside my confusion about top-level "def"s (which may be
orthogonal to my questions about "instance_eval"):

Rick Denatale wrote:
> rb_obj_instance_eval sets the klass argument to the singleton_class of
> the receiver (creating it if it doesn't already exist), unless the
> receiver is an immediate object (a Fixnum, or nil, true, or false) in
> which case it sets klass to nil.

I would have guessed that the klass argument would be the context in
which constants and "def"s are evaluated. But we've already seen that
this is not true (re the constants).

So far as I can guess, this klass argument seems to affect "def"s AND
NOTHING ELSE. Can that be? (If so, all my questions are answered. But
I may have a comment or two.)
--
Posted via http://www.ruby-....

Xavier Noria

11/17/2007 5:21:00 AM

0

On Nov 16, 2007, at 11:00 PM, Rick DeNatale wrote:

> It only affects the execution context by binding self to the instance,
> NOT the lexical context.

This is related to another thread about constant name resolution
(subject "constant name resolution and module_eval").

Why then *_eval (BLOCK|STRING) behave different?

C = "Object"

class String
C = "String"
end

a = ''
a.instance_eval do
def c_in_block; C; end
end

a.instance_eval <<EOS
def c_in_string; C; end
EOS

puts a.c_in_block # -> Object
puts a.c_in_string # -> String

Looks like there's a "current" module for constant name resolution,
and another "current" module for method definition etc.

-- fxn


Raul Raul

11/17/2007 6:41:00 AM

0

Rick Denatale wrote:

> Now all this begged a question in my mind. That is, what's the
> difference between instance_eval and class_eval (with its alias
> module_eval). A little digging in the 1.8.6 MRI code reveals that
> both use the same underlying code, but the inner c function
> specific_eval (in eval.c) takes both a klass and a self argument.
>
> Both rb_object_instance_eval (the code behind Kernel#instance_eval)
> and rb_mod_module_eval (the code behind both Module#module_eval and
> Module#class_eval) set the self argument to the receiver.
>
> rb_obj_instance_eval sets the klass argument to the singleton_class of
> the receiver (creating it if it doesn't already exist), unless the
> receiver is an immediate object (a Fixnum, or nil, true, or false) in
> which case it sets klass to nil.
> ...

Very nice analysis work; with the Figure 24.2 (made famous by Gregg) of
the Pickaxe at hand, and Rick's detailed description of the klass
pointer adventures, we can now connect the dots (at least, most of
them).

Bravo!

Raul

--
Posted via http://www.ruby-....

Greg Weeks

11/17/2007 9:29:00 AM

0

Xavier Noria wrote:
> C = "Object"
>
> class String
> C = "String"
> end
>
> a = ''
> a.instance_eval do
> def c_in_block; C; end
> end
>
> a.instance_eval <<EOS
> def c_in_string; C; end
> EOS
>
> puts a.c_in_block # -> Object
> puts a.c_in_string # -> String

The more that I think about scoping in the context of

closures define_method instance_eval module_eval eval

the more confused I get. Alas, I've never seen a formal description of
the Ruby execution model. There seems to be a current self and a
current klass, but I don't know exactly how they are set and used.

I'll just say here that your fine example can be simplified a little:

a.instance_eval { C } -> "Object"
a.instance_eval "C" -> "String"
--
Posted via http://www.ruby-....

Greg Weeks

11/17/2007 11:28:00 PM

0

Raul Parolari wrote:
> we can now connect the dots (at least, most of them).

Ah, but I still wonder what the internal variable 'klass' affects. So
far, 'klass' seems to affect:

- where a def method is stored
- where constants in string evals are looked up

But I don't know.
--
Posted via http://www.ruby-....