Instance Eval of a Proc

Why can I not use a Proc created from a method in #instance_eval? (Or rather, am I making a mistake, or is there a way to do this?)

Related: are first-class functions planned for 2.0? The whole Proc/block/method situation needs unifying and simplifying, IMHO.

[Slim:~/Desktop] gavinkis% cat instance_eval_proc.rb
    class Foo
      def self.show_name( *args )
        puts "Foo.show_name says that @name is '#@name' for #{self.inspect}"
      end
      def initialize( name )
        @name = name
      end
    end

    f = Foo.new( "Jim" )

    my_lambda = lambda{
      puts "my_lambda says that @name is '#@name' for #{self.inspect}"
    }
    p my_lambda
    f.instance_eval( &my_lambda )

    my_proc = Proc.new{
      puts "my_proc says that @name is '#@name' for #{self.inspect}"
    }
    p my_proc
    f.instance_eval( &my_proc )

    meth_lambda = Foo.method( :show_name ).to_proc
    p meth_lambda
    f.instance_eval( &meth_lambda )

[Slim:~/Desktop] gavinkis% ruby instance_eval_proc.rb
    #<Proc:0x001ca42c@instance_eval_proc.rb:12>
    my_lambda says that @name is 'Jim' for #<Foo:0x1c9d24 @name="Jim">
    #<Proc:0x001ca10c@instance_eval_proc.rb:18>
    my_proc says that @name is 'Jim' for #<Foo:0x1c9d24 @name="Jim">
    #<Proc:0x001c9bf8@instance_eval_proc.rb:24>
    Foo.show_name says that @name is '' for Foo

[Slim:~/Desktop] gavinkis% ruby --version
    ruby 1.8.2 (2004-12-25) [powerpc-darwin8.0.0]

[Slim:~/Desktop] gavinkis% uname -a
    Darwin Slim.local 8.2.0 Darwin Kernel Version 8.2.0: Fri Jun 24 17:46:54 PDT 2005; root:xnu-792.2.4.obj~3/RELEASE_PPC Power Macintosh powerpc

just because you are call meth_lambda in instance_eval doesn't mean @name will
be defined. imagine that you'd written this instead

   f.instance_eval{ Foo::show_name }

of course this is exactly what's happening - you've used the class Foo to look
up a class method that prints an uninitialized class variable. the fact that
this whole business gets wrapped in another proc
(Foo.method(:show_name).to_proc) still doesn't initialize it nor bind the
instance's @name to the class @name somehow. probably doing something like

   f.instance_eval do
     f.class.instance_eval{ @name = 'Jim' }
     meth_lambda.call
   end

might though.

another approach would be (i think) to 'install' the class method as an
instance one using define_method or something.

cheers.

-a

···

On Wed, 20 Jul 2005, Gavin Kistner wrote:

Why can I not use a Proc created from a method in #instance_eval? (Or rather, am I making a mistake, or is there a way to do this?)

Related: are first-class functions planned for 2.0? The whole Proc/ block/method situation needs unifying and simplifying, IMHO.

[Slim:~/Desktop] gavinkis% cat instance_eval_proc.rb
  class Foo
    def self.show_name( *args )
      puts "Foo.show_name says that @name is '#@name' for #{self.inspect}"
    end
    def initialize( name )
      @name = name
    end
  end

  f = Foo.new( "Jim" )

  my_lambda = lambda{
    puts "my_lambda says that @name is '#@name' for #{self.inspect}"
  }
  p my_lambda
  f.instance_eval( &my_lambda )

  my_proc = Proc.new{
    puts "my_proc says that @name is '#@name' for #{self.inspect}"
  }
  p my_proc
  f.instance_eval( &my_proc )

  meth_lambda = Foo.method( :show_name ).to_proc
  p meth_lambda
  f.instance_eval( &meth_lambda )

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso

===============================================================================

I think Gavin's point is that it *does* work for my_lambda and
my_proc. meth_lambda is the only exception. Neither my_lambda nor
my_proc knew about @name either when they were defined. instance_eval
bound self to the caller for the evaluation of the proc. However, the
same binding didn't take place for meth_lambda, and it used Foo as
self instead of f.

My guess as to the reason for this is that instance_eval will _supply_
a binding for self where there was none, but won't/can't _override_ an
existing binding for self. Since meth_lambda already has Foo bound to
self, f isn't bound and you get the observed behavior.

That said, if we have to ability to supply a binding to self, it's
hard to believe that we _can't_ override an existing binding. That
would suggest that either:

1) It's a design decision to not override an existing binding for self
2) It's an oversight that can be fixed

Anyone more familiar with the internals want to judge between those
options (or propose a third)?

Jacob Fugal

···

On 7/19/05, Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

On Wed, 20 Jul 2005, Gavin Kistner wrote:

> [Slim:~/Desktop] gavinkis% cat instance_eval_proc.rb
> class Foo
> def self.show_name( *args )
> puts "Foo.show_name says that @name is '#@name' for #{self.inspect}"
> end
> def initialize( name )
> @name = name
> end
> end
>
> f = Foo.new( "Jim" )
>
> my_lambda = lambda{
> puts "my_lambda says that @name is '#@name' for #{self.inspect}"
> }
> p my_lambda
> f.instance_eval( &my_lambda )
>
> my_proc = Proc.new{
> puts "my_proc says that @name is '#@name' for #{self.inspect}"
> }
> p my_proc
> f.instance_eval( &my_proc )
>
> meth_lambda = Foo.method( :show_name ).to_proc
> p meth_lambda
> f.instance_eval( &meth_lambda )

just because you are call meth_lambda in instance_eval doesn't mean
@name will be defined.

the fact that this whole business gets wrapped in another proc
(Foo.method(:show_name).to_pro­c) still doesn't initialize it nor bind the
instance's @name to the class @name somehow.

Perhaps this is the source of my confusion. Are you saying that:
  my_proc = inst.method( :method_name ).to_proc
is equivalent to:
  my_proc = Proc.new{ inst.call( :method_name ) }
and not (as I had assumed):
  my_proc = inst.method( :method_name ).unbind.turn_into_a_proc

The documentation is somewhat terse on this matter. Method#to_proc
simply says "Returns a Proc object corresponding to this method."

well:

   harp:~ > ri Object.method

   ---------------------------------------------------------- Object#method
        obj.method(sym) => method

···

On Wed, 20 Jul 2005, Jacob Fugal wrote:

On 7/19/05, Ara.T.Howard <Ara.T.Howard@noaa.gov> wrote:

On Wed, 20 Jul 2005, Gavin Kistner wrote:

[Slim:~/Desktop] gavinkis% cat instance_eval_proc.rb
  class Foo
    def self.show_name( *args )
      puts "Foo.show_name says that @name is '#@name' for #{self.inspect}"
    end
    def initialize( name )
      @name = name
    end
  end

  f = Foo.new( "Jim" )

  my_lambda = lambda{
    puts "my_lambda says that @name is '#@name' for #{self.inspect}"
  }
  p my_lambda
  f.instance_eval( &my_lambda )

  my_proc = Proc.new{
    puts "my_proc says that @name is '#@name' for #{self.inspect}"
  }
  p my_proc
  f.instance_eval( &my_proc )

  meth_lambda = Foo.method( :show_name ).to_proc
  p meth_lambda
  f.instance_eval( &meth_lambda )

just because you are call meth_lambda in instance_eval doesn't mean
@name will be defined.

I think Gavin's point is that it *does* work for my_lambda and
my_proc. meth_lambda is the only exception. Neither my_lambda nor
my_proc knew about @name either when they were defined. instance_eval
bound self to the caller for the evaluation of the proc. However, the
same binding didn't take place for meth_lambda, and it used Foo as
self instead of f.

   ------------------------------------------------------------------------
        Looks up the named method as a receiver in _obj_, returning a
        +Method+ object (or raising +NameError+). The +Method+ object acts
        as a closure in _obj_'s object instance, so instance variables and
        the value of +self+ remain available.
   ...

so i don't really see the exception - the behaviour of Foo.method(:show_name)
does exactly as advertised - binding the method to the class Foo along with
that notion of self and instance vars. so the binding of self for the
duration of instance_eval is definitely working - what gavin is attempting to
do is akin to hoping

   f.instance_eval do
     p ::File::LOCK_EX
   end

would somehow print some other class/objects constant named 'LOCK_EX' in that
the caller/scope-resolution for show_name is already set after the call to
Foo::method. in the cases like

   f.instance_eval &my_proc

it has not already been set and is then set for the call. eg. Foo::method
binds exactly as f.instance_eval does - only a layer deeper.

anyhow it seems consistent - but perhaps not intuitive.

kind regards.

-a
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso

===============================================================================

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

the behaviour of Foo.method(:show_name) does exactly as
advertised - binding the method to the class Foo along
with that notion of self and instance vars.

That is not in dispute.

so the binding of self for the duration of instance_eval
is definitely working

Wait, wait, wait... timeout!

Isn't the whole point of ‘instance_eval’ to change the
binding of ‘self’?

(I must admit I never fully understood the scoping rules,
especially when various kinds of ‘eval’ is involved.)

[...]

in the cases like

   f.instance_eval &my_proc

it has not already been set and is then set for the call.
eg. Foo::method binds exactly as f.instance_eval does -
only a layer deeper.

So, in Ruby, there are two kinds of procs — ones that are
bound “deeply”, and ones that are bound “shallowly”? Well,
that's an interesting concept.

anyhow it seems consistent - but perhaps not intuitive.

It seems consistent to me only after you introduced the
concept of “deeply-bound” vs. “shallowly-bound” procs.

···

--
Daniel Brockman <daniel@brockman.se>

    So really, we all have to ask ourselves:
    Am I waiting for RMS to do this? --TTN.

Indeed. "Fighting ri with ri", we have from ri Object#instance_eval:

     Evaluates a string containing Ruby source code, or the given block,
     within the context of the receiver (_obj_). In order to set the
     context, the variable +self+ is set to _obj_ while the code is
     executing, giving the code access to _obj_'s instance variables.

So, according to documentation, instance_eval should set +self+ to
_obj_ while the code is executing. However, this binding doesn't
happen if there's already a binding for self. Question is, should it?
If so, there's a bug. If not, the documentation needs to reflect that.

Jacob Fugal

···

On 7/19/05, Daniel Brockman <daniel@brockman.se> wrote:

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

> the behaviour of Foo.method(:show_name) does exactly as
> advertised - binding the method to the class Foo along
> with that notion of self and instance vars.

That is not in dispute.

> so the binding of self for the duration of instance_eval
> is definitely working

Wait, wait, wait... timeout!

Isn't the whole point of 'instance_eval' to change the
binding of 'self'?

the docs are consistent, let me show it another way:

   harp:~ > cat a.rb
   class C

···

On Wed, 20 Jul 2005, Jacob Fugal wrote:

On 7/19/05, Daniel Brockman <daniel@brockman.se> wrote:

"Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

the behaviour of Foo.method(:show_name) does exactly as
advertised - binding the method to the class Foo along
with that notion of self and instance vars.

That is not in dispute.

so the binding of self for the duration of instance_eval
is definitely working

Wait, wait, wait... timeout!

Isn't the whole point of 'instance_eval' to change the
binding of 'self'?

Indeed. "Fighting ri with ri", we have from ri Object#instance_eval:

    Evaluates a string containing Ruby source code, or the given block,
    within the context of the receiver (_obj_). In order to set the
    context, the variable +self+ is set to _obj_ while the code is
    executing, giving the code access to _obj_'s instance variables.

So, according to documentation, instance_eval should set +self+ to
_obj_ while the code is executing. However, this binding doesn't
happen if there's already a binding for self. Question is, should it?
If so, there's a bug. If not, the documentation needs to reflect that.

   #
   # this operates similarly to 'method'
   #
     def C::self_boxed
       self.instance_eval{ self }
     end
   end

   a = Array::new
   h = Hash::new

   a.instance_eval{ p [self, C::self_boxed] }
   h.instance_eval{ p [self, C::self_boxed] }

   harp:~ > ruby a.rb
   [, C]
   [{}, C]

this is similar to the way Class::method works - self has already been
over-ridden. so in a case like

   obj = Object::new
   class C; end

   obj.instance_eval{ C::method('some_method').to_proc.call }

then we have the case where 'self' is first swapped to 'obj' in order to call
a block that then swaps 'self' for 'C'. so no matter how we wrap

   C::method('some_method').to_proc.call

we will always find 'self' == C when we call the proc returns off of the
Method object which wraps 'some_method'. that's because it works in a way
roughly similar to 'self_boxed' in that it's already set up a layer of self
swap'ing.

one more example:

   harp:~ > cat a.rb
   a = 'a'
   b = 'b'

   la = lambda{ a.instance_eval{ self } }
   lb = lambda{ b.instance_eval{ [la(), self] } }

   p lb()

   harp:~ > ruby a.rb
   ["a", "b"]

so you can't override self in a block that overrides self and Class#method is
just that kind of method. uggh that's confusing. :wink:

cheers.

-a
--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
My religion is very simple. My religion is kindness.
--Tenzin Gyatso

===============================================================================

"Ara.T.Howard" <Ara.T.How...@noaa.gov> writes:
[a bunch of snipped examples]

Ara, thanks for helping investigate this. Your C::self_boxed method is
being called with an explicit receiver (C), which is, of course, what
I'm trying to avoid/change using instance_eval.

Two examples from languages with first-class functions:
Lua:
  C = { name='C' }
  function C:show_name( )
    print( self.name )
  end

  b = { name='bob' }
  C.show_name( b ) --> "bob"
  -- Here, 'b' is being passed as the first implicit
  -- 'self' parameter to show_name

JavaScript:
  Array.prototype.show_length = function( ){
    alert( this.length )
  }
  var a = [1,2,3];
  var foo = "I'm a string with a length property";
  a.show_length.call( foo ); //"35"
  //a.show_length looks up the Function instance
  //which has a "call" method that allows you to change
  //the scope of 'this'

I know that Ruby doesn't currently have first-class functions, but I'm
trying to determine if there's a way to do the equivalent of the above.
Is there any way to invoke a method defined on one class within the
scope of an instance of any other class?

Phrogz schrieb:

I know that Ruby doesn't currently have first-class functions, but I'm
trying to determine if there's a way to do the equivalent of the above.

As has been shown in the original post, Ruby's lambdas are what you call first-class functions. When called via instance_eval, they are executed within a new self and have access to self's instance variables and methods.

Is there any way to invoke a method defined on one class within the
scope of an instance of any other class?

It seems that a method, even if unbound or converted to a proc, always keeps a connection to its class. I think the only way I've seen yet to achieve what you want was using the evil library.

Regards,
Pit

Pit Capitain wrote:

As has been shown in the original post, Ruby's lambdas are what you call
first-class functions. When called via instance_eval, they are executed
within a new self and have access to self's instance variables and methods.

Ack, very true. I withdraw that statement. It's just that (as you say)
the current implementation of methods does not have them being
first-class functions. (From my tests, it looks like blocks, however,
are.)