Forum: Ruby How does top level method is being called Inside the block with instance_eval?

249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-10-28 16:21
Hi,

Follow the code below :

class Foo
    def initialize
       @var = 1
  end

  private

  def bar
     11
  end
end

p foo = Foo.new # #<Foo:0x1fc41f0 @var=1>

def baz;13;end

foo.instance_eval do
   p self # #<Foo:0x1fc41f0 @var=1>
   p bar  # 11
   p @var # 1
   p baz  # 13
end

Now foo.instance_eval set `self` as foo. Then how the call to method
`baz` is allowed inside the block? What is the theory behind it?
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-10-28 16:33
(Received via mailing list)
On Mon, Oct 28, 2013 at 4:21 PM, Love U Ruby <lists@ruby-forum.com>
wrote:
>
>    p self # #<Foo:0x1fc41f0 @var=1>
>    p bar  # 11
>    p @var # 1
>    p baz  # 13
> end
>
> Now foo.instance_eval set `self` as foo. Then how the call to method
> `baz` is allowed inside the block? What is the theory behind it?

It's because methods defined in the top level end up being defined as
private methods of Object, and as all classes in the end inherit from
object, you can call that method from within any instance of any
object:

2.0.0-p195 :001 > s = "1234"
 => "1234"
2.0.0-p195 :002 > def foo; puts "this is foo"; end
 => nil2.0.0-p195 :004 > s.instance_eval {foo}
this is foo
2.0.0-p195 :009 > Object.private_methods.grep(/foo/)
 => [:foo]
2.0.0-p195 :010 > String.private_methods.grep(/foo/)
 => [:foo]



Jesus.
9fbce8702731e0b99b22e2c87b46e7ed?d=identicon&s=25 Lynks DuNord (Guest)
on 2013-10-28 16:36
(Received via mailing list)
unsubscribe


2013/10/28 Jess Gabriel y Galn <jgabrielygalan@gmail.com>
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-10-28 16:44
"Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> wrote in post
#1125896:
> On Mon, Oct 28, 2013 at 4:21 PM, Love U Ruby <lists@ruby-forum.com>

> It's because methods defined in the top level end up being defined as
> private methods of Object, and as all classes in the end inherit from
> object, you can call that method from within any instance of any
> object:

Thanks for your answer. How would you explain in case of local variables
:

class Foo
    def initialize
       @var = 1
  end

  private

  def bar
     11
  end
end

foo = Foo.new # #<Foo:0x1fc41f0 @var=1>

baz = 2

foo.instance_eval do
   p baz # 2 <- why not error?
end
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-10-28 16:50
(Received via mailing list)
On Mon, Oct 28, 2013 at 4:44 PM, Love U Ruby <lists@ruby-forum.com>
wrote:
> :
>   end
> end
>
> foo = Foo.new # #<Foo:0x1fc41f0 @var=1>
>
> baz = 2
>
> foo.instance_eval do
>    p baz # 2 <- why not error?
> end

Because blocks (do...end) are closures and have access to their
surrounding scope. instance_eval is just a regular method to which a
block is passed, no new scope is created. This is in contrast to some
keywords like def or class, which create a new scope that is not a
closure.

Jesus.
249c7fd851c5c5ac5a1abdb756472ae1?d=identicon&s=25 Arup Rakshit (my-ruby)
on 2013-10-28 17:00
"Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> wrote in post
#1125900:
> On Mon, Oct 28, 2013 at 4:44 PM, Love U Ruby <lists@ruby-forum.com>

> Because blocks (do...end) are closures and have access to their
> surrounding scope. instance_eval is just a regular method to which a
> block is passed, no new scope is created. This is in contrast to some
> keywords like def or class, which create a new scope that is not a
> closure.

Excellent!

class Foo
    def initialize
       @var = 1
  end

  private

  def bar
     11
  end
end

foo = Foo.new # #<Foo:0x1fc41f0 @var=1>

@x,@@y = 10,11

foo.instance_eval do
   p @x  # nil # why nil ?
   p @@y # 11  # why not nil ?
end
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 "Jesús Gabriel y Galán" <jgabrielygalan@gmail.com> (Guest)
on 2013-10-28 17:12
(Received via mailing list)
On Mon, Oct 28, 2013 at 5:00 PM, Love U Ruby <lists@ruby-forum.com>
wrote:
> Excellent!
>   end
> end
>
> foo = Foo.new # #<Foo:0x1fc41f0 @var=1>
>
> @x,@@y = 10,11
>
> foo.instance_eval do
>    p @x  # nil # why nil ?
>    p @@y # 11  # why not nil ?
> end

Variables that start with @ are instance variables. Instance variables
belong to the instance where they are assigned a value. In this case,
@x is defined in the top level, so it belongs to the top level object
only, the one "called" main. You cannot see it from anywhere else and
is not related to the inheritance or anything like that. When you call
instance_eval, self is set to the instance it is being called on, in
this case foo, so @x is looked up in that object, where it doesn't
exist, so it's nil.

On the other hand, variables that start with @@ are class variables,
and are inherited by all subclasses. The class variable @@y defined in
the top level scope ends up being defined in Object:

2.0.0-p195 :001 > @@y = 11
(irb):1: warning: class variable access from toplevel
 => 11
2.0.0-p195 :002 > Object.class_variables
 => [:@@y]

so it's accessible from any subclass of Object (basically any object):

2.0.0-p195 :021 > class Foo
2.0.0-p195 :022?>   def y
2.0.0-p195 :023?>     @@y
2.0.0-p195 :024?>     end
2.0.0-p195 :025?>   end
 => nil
2.0.0-p195 :026 > Foo.new.y
 => 11

Jesus.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.