Getting the binding of the caller

Hi,

Is there a way to get the binding of the caller?

   class A
     def m(b=binding)
       eval("self", b)
     end
   end

   A.new.m # => #<A:0x81e1bec>
   A.new.m(binding) # => main

What I want is exactly the second, but without specifying "binding" explicitly.

Possible or not?

Regards,

   Michael

Michael Neumann wrote:

Hi,

Moin!

Is there a way to get the binding of the caller?

Yup, there is. See the attached file. It's a bit obscure, but it works and shouldn't be too slow.

Regards,
  Michael

More regards,
Florian Gross

binding_of_caller.rb (2 KB)

It's been discussed on -talk this year, so a search in the archive for
'binding' should help. Someone posted a continuations-based solution
that gives you basically what you want, but at considerable runtime
expense, IIRC.

There's no plain-Ruby solution; i.e. the language doesn't go out of
its way to help you here. There's an RCR for it; can't remember which
one.

However, blocks can be useful here, and may just be good enough for
you.

  def trace(&block)
    expr = block.call
    value = eval expr, block
    puts "#{expr} = #{value}"
  end

  def foo
    x = 5
    y = 12
    trace { "Math.sqrt( x**2 + y**2 )" }
  end

I gotta say that's pretty handy.

Cheers,
Gavin

···

On Wednesday, August 18, 2004, 8:52:18 AM, Michael wrote:

Hi,

Is there a way to get the binding of the caller?

   class A
     def m(b=binding)
       eval("self", b)
     end
   end

   A.new.m # => #<A:0x81e1bec>
   A.new.m(binding) # => main

What I want is exactly the second, but without specifying "binding"
explicitly.

Possible or not?

--
Gavin's vim tip for the day: ':help text-objects'

Sure.
Take a look at Florian Groß' Binding.of_caller at
http://noegnud.sourceforge.net/flgr/binding_of_caller.rb

In some contexts, you can avoid the overhead of #callcc, but you get an
ugly interface in exchange.

···

On Wed, Aug 18, 2004 at 07:52:18AM +0900, Michael Neumann wrote:

Hi,

Is there a way to get the binding of the caller?

  class A
    def m(b=binding)
      eval("self", b)
    end
  end

  A.new.m # => #<A:0x81e1bec>
  A.new.m(binding) # => main

What I want is exactly the second, but without specifying "binding"
explicitly.

Possible or not?

--
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Florian Gross wrote:

Michael Neumann wrote:

Is there a way to get the binding of the caller?

Yup, there is. See the attached file. It's a bit obscure, but it works and shouldn't be too slow.

Thanks for the quick answer... uhm, but it does seem to behave as it should:

   require 'binding_of_caller'
   class A
     def m
       Binding.of_caller do |binding|
         eval("self", binding)
       end
     end
   end

   p A.new.m # => #<A:0x8115a14>

I expect "self" to be "main".

Regards,

   Michael

Gavin Sinclair wrote:

It's been discussed on -talk this year, so a search in the archive for
'binding' should help. Someone posted a continuations-based solution
that gives you basically what you want, but at considerable runtime
expense, IIRC.

There's no plain-Ruby solution; i.e. the language doesn't go out of
its way to help you here. There's an RCR for it; can't remember which
one.

However, blocks can be useful here, and may just be good enough for
you.

Thanks, this trick did it for me. Of course, it's not 100% perfect but that doesn't matter.

Regards,

   Michael

Michael Neumann wrote:

Thanks for the quick answer... uhm, but it does seem to behave as it should:

  require 'binding_of_caller'
  class A
    def m
      Binding.of_caller do |binding|
        eval("self", binding)
      end
    end
  end

  p A.new.m # => #<A:0x8115a14>

I expect "self" to be "main".

That's weird -- can't find an explanation for it, because the following works:

require 'binding_of_caller'
this = self
class A
   def m
     Binding.of_caller do |binding|
       eval("this", binding)
     end
   end
end

p A.new.m # => main

Maybe somebody has the knowledge needed to explain what's going on there?

Regards,
  Michael

More regards,
Florian Gross

Florian Gross wrote:

Michael Neumann wrote:

Thanks for the quick answer... uhm, but it does seem to behave as it should:

  require 'binding_of_caller'
  class A
    def m
      Binding.of_caller do |binding|
        eval("self", binding)
      end
    end
  end

  p A.new.m # => #<A:0x8115a14>

I expect "self" to be "main".

That's weird -- can't find an explanation for it, because the following works:

require 'binding_of_caller'
this = self
class A
  def m
    Binding.of_caller do |binding|
      eval("this", binding)
    end
  end
end

p A.new.m # => main

Maybe somebody has the knowledge needed to explain what's going on there?

Hm, it still doesn't work in my special case, as I get a
"Binding.of_caller used in non-method context or trailing statements of method using it aren't in the block." exception (and I really don't understand how this Binding.of_caller really works ;-):

require 'binding_of_caller'

class Decorator
   def initialize(&block)
     @block = block
   end

   def >>(meth_id)
     obj = Binding.of_caller do |binding|
       eval("this", binding)
     end
     old = method(meth_id)
     new = @block.call(old)

     # the line below is why I need the Binding.of_caller
     obj.class.send(:define_method, meth_id, new)
   end
end

def wrapwith(value)
   Decorator.new {|old|
     proc {|*args|
       print "##", value, "\n"
       old.call(*args)
     }
   }
end

wrapwith(42) >>
def f(x) x * 2 end

p f(4)

···

##############

Regards,

   Michael

Michael Neumann wrote:

Hm, it still doesn't work in my special case, as I get a
"Binding.of_caller used in non-method context or trailing statements of method using it aren't in the block." exception (and I really don't understand how this Binding.of_caller really works ;-):

It works by installing a temporary trace_func. trace_funcs get an event on returns from methods and the binding of the context you where in before the method returned. Using continuations Binding.of_caller will first let method return, grab the binding of the caller, go back to the Binding.of_caller call and this time execute the block. If I wouldn't raise the exception you mentioned above then statements that aren't in the block would be executed twice. This is why there can be no code outside of the Binding.of_caller block after the call to it.

This ought to work, however I find the 'this = self' line quite ugly -- I still need to find out why just using self doesn't work and if it can be solved. (It appears like the binding which I get from the trace_func is nested into the original binding which is why variables can be accessed, but not the original binding itself which is why self and method calls don't work.)

I couldn't test this code (haven't applied your def -> symbol patch) so there might still be a bug in it that I overlooked.

require 'binding_of_caller'

class Decorator
   def initialize(&block)
     @block = block
   end

   def >>(meth_id)
     Binding.of_caller do |context|
       obj = eval("this", context)
       old = obj.method(meth_id)
       new = @block.call(old)

       # the line below is why I need the Binding.of_caller
       obj.class.send(:define_method, meth_id, new)
     end
   end
end

def wrapwith(value)
   Decorator.new {|old|
     proc {|*args|
       print "##", value, "\n"
       old.call(*args)
     }
   }
end

this = self
wrapwith(42) >>
def f(x) x * 2 end

p f(4)

Regards,
  Michael

More regards,
Florian Gross

Florian Gross wrote:

Michael Neumann wrote:

Hm, it still doesn't work in my special case, as I get a
"Binding.of_caller used in non-method context or trailing statements of method using it aren't in the block." exception (and I really don't understand how this Binding.of_caller really works ;-):

It works by installing a temporary trace_func. trace_funcs get an event on returns from methods and the binding of the context you where in before the method returned. Using continuations Binding.of_caller will first let method return, grab the binding of the caller, go back to the Binding.of_caller call and this time execute the block. If I wouldn't raise the exception you mentioned above then statements that aren't in the block would be executed twice. This is why there can be no code outside of the Binding.of_caller block after the call to it.

Thanks for this explanation. Now I understand. It's a bit like a time travel :wink:

This ought to work, however I find the 'this = self' line quite ugly -- I still need to find out why just using self doesn't work and if it can be solved. (It appears like the binding which I get from the trace_func is nested into the original binding which is why variables can be accessed, but not the original binding itself which is why self and method calls don't work.)

I couldn't test this code (haven't applied your def -> symbol patch) so there might still be a bug in it that I overlooked.

This should do it for you:

   this = self
   def f(x) x * 2 end
   wrapwith(42) >> :f

Regards,

   Michael