Help with tricky proc/binding issue

i'm trying to be able to define a proc that can be called in the context of
self, eg:

   block = lambda{ p 42 }
   an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary ruby):

   b = lambda{|x| p [x, y]}

   class C
     def y; 42; end
   end

   c = C::new
   x = 42

   c.arg_instance_eval(x, &b) #=> [42, 42]

any ideas?

-a

···

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

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

Hi,

···

In message "Re: help with tricky proc/binding issue" on Mon, 19 Sep 2005 23:42:12 +0900, "Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

i'm trying to be able to define a proc that can be called in the context of
self, eg:

  block = lambda{ p 42 }
  an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary ruby):

I understand what you want. But I haven't come up with a good name
for the function yet.

              matz.

Ara.T.Howard wrote:

i'm trying to be able to define a proc that can be called in the
context of self, eg:

   block = lambda{ p 42 }
   an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary
ruby):

   b = lambda{|x| p [x, y]}

   class C
     def y; 42; end
   end

   c = C::new
   x = 42

   c.arg_instance_eval(x, &b) #=> [42, 42]

any ideas?

The only workaround that comes to mind is to pass self explicitely along
with other arguments. Or use a trick with delegation that allows to do
instance_eval on a proxy self that will also provide arguments given.

    robert

Ara.T.Howard schrieb:

i'm trying to be able to define a proc that can be called in the context of
self, eg:

  block = lambda{ p 42 }
  an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary ruby):

  b = lambda{|x| p [x, y]}

  class C
    def y; 42; end
  end

  c = C::new
  x = 42

  c.arg_instance_eval(x, &b) #=> [42, 42]

any ideas?

Tom (aka Trans) recently mentioned that he changed procs into methods in order to get what you want. Here's a quick hack, not efficient and not thread-safe, but maybe a start:

   class Object
     def arg_instance_eval( *args, &block )
       c = class << self; self; end
       c.send( :define_method, :arg_instance_eval_method, &block )
       arg_instance_eval_method( *args )
     ensure
       c.send( :remove_method, :arg_instance_eval_method )
     end
   end

   b = lambda{|x| p [x, y]}

   class C
     def y; 42; end
   end

   c = C::new
   z = 41

   c.arg_instance_eval( z, &b ) # => [41, 42]

Regards,
Pit

Ara.T.Howard wrote:

i'm trying to be able to define a proc that can be called in the context of
self, eg:

  block = lambda{ p 42 }
  an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary ruby):

Currently the only way of doing this is Proc#self= from evil.rb...

maybe

   class Object
     def evaluate(*args, &block)
       ...
     end
   end

??

another option would be to turn the problem inside out and do something like

   l = lambda{ p x }
   l.self = obj
   l.call

this is what i have so far:

   [ahoward@localhost ~]$ cat a.rb
   class Object
     def evaluate(*a, &b)
       m = "____eval____#{ rand(65536) }____"
       klass = Class === self ? self : self::class
       klass.module_eval{ define_method m, &b }
       begin
         send m, *a
       ensure
         klass.module_eval{ remove_method m }
       end
     end
   end

   class C
     def y
       42
     end
   end

   b = lambda{|x| p [x, y, self]}

   c = C::new
   x = 42
   c.evaluate(x, &b) #=> [42, 42, #<C:0xb7f2f5c0>]

   [ahoward@localhost ~]$ ruby a.rb
   [42, 42, #<C:0xb7f1b5c0>]

thoughts?

-a

···

On Mon, 19 Sep 2005, Yukihiro Matsumoto wrote:

Hi,

In message "Re: help with tricky proc/binding issue" > on Mon, 19 Sep 2005 23:42:12 +0900, "Ara.T.Howard" <Ara.T.Howard@noaa.gov> writes:

>i'm trying to be able to define a proc that can be called in the context of
>self, eg:
>
> block = lambda{ p 42 }
> an_obj.instance_eval &block
>
>but which can also be called with arguments, for example (imaginary ruby):

I understand what you want. But I haven't come up with a good name
for the function yet.

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

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

Yukihiro Matsumoto wrote:

>i'm trying to be able to define a proc that can be called in the context of
>self, eg:
>
> block = lambda{ p 42 }
> an_obj.instance_eval &block
>
>but which can also be called with arguments, for example (imaginary ruby):

I understand what you want. But I haven't come up with a good name
for the function yet.

What about Proc#with_self() that will return a new proc similar to the current one, but with a changed self context?

Pit Capitain wrote:

Ara.T.Howard schrieb:

i'm trying to be able to define a proc that can be called in the
context of self, eg:

  block = lambda{ p 42 }
  an_obj.instance_eval &block

but which can also be called with arguments, for example (imaginary
ruby):

  b = lambda{|x| p [x, y]}

  class C
    def y; 42; end
  end

  c = C::new
  x = 42

  c.arg_instance_eval(x, &b) #=> [42, 42]

any ideas?

Tom (aka Trans) recently mentioned that he changed procs into methods
in order to get what you want. Here's a quick hack, not efficient and
not thread-safe, but maybe a start:

   class Object
     def arg_instance_eval( *args, &block )
       c = class << self; self; end
       c.send( :define_method, :arg_instance_eval_method, &block )
       arg_instance_eval_method( *args )
     ensure
       c.send( :remove_method, :arg_instance_eval_method )
     end
   end

Hacky but nice! For thread safety how about:

   class Object
     def arg_instance_eval( *args, &block )
       c = class << self; self; end
       meth = "__m_#{Thread.current.object_id}_#{rand 666}"
       c.send( :define_method, meth, &block )
       send( meth, *args )
     ensure
       c.send( :remove_method, meth )
     end
   end

Kind regards

    robert

that's funny. here's my current hack:

   class Object
     def evaluate(*a, &b)
       ret, sent = nil
       loop do
         m = "____evaluate____#{ rand(42) }____#{ rand(42) }____"
         klass = Class === self ? self : self::class
         begin
           klass.module_eval{ define_method m, &b }
           ret = send(sent = m, *a)
         ensure
           begin
             klass.module_eval{ remove_method m }
           ensure
             break if sent
           end
         end
       end
       ret
     end
   end

   class C
     def y
       42
     end
   end

   b = lambda{|x| p [x, y, self]}

   c = C::new
   x = 42
   c.evaluate(x, &b) #=> [42, 42, #<C:0xb7f2f5c0>]

guess that's the way to go for now.

cheers.

-a

···

On Tue, 20 Sep 2005, Pit Capitain wrote:

any ideas?

Tom (aka Trans) recently mentioned that he changed procs into methods in
order to get what you want. Here's a quick hack, not efficient and not
thread-safe, but maybe a start:

class Object
   def arg_instance_eval( *args, &block )
     c = class << self; self; end
     c.send( :define_method, :arg_instance_eval_method, &block )
     arg_instance_eval_method( *args )
   ensure
     c.send( :remove_method, :arg_instance_eval_method )
   end
end

b = lambda{|x| p [x, y]}

class C
   def y; 42; end
end

c = C::new
z = 41

c.arg_instance_eval( z, &b ) # => [41, 42]

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

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

Ara.T.Howard wrote:

another option would be to turn the problem inside out and do something like

  l = lambda{ p x }
  l.self = obj
  l.call

Procs are currently immutable and I'd assume that the source code assumes that they can not be changed in several places. It's less risky to return a new object with a changed self context, IMHO.

I've talked about this before, but the ability to return a new
proc with local variables manipulated would also be nice:

- Make "local" variables really local to the proc. Initialize
these to the current values of the local variables in the
previous binding. Effectively, this gives the proc its own
local binding (at least for "local" variables). This could be
done in conjunction with redefining self for the proc to.

It would also be nice to be able to be able to do the same
thing for blocks easily so that you could easily localize your
"local" variables in your block. But, you could emulate that
as long as you had a way to localize proc local variables:

foo(&(lambda{...}.localize))

or if you could do it directly to a block you may have some
syntax like this:

foo {{...}} # double braces to represent localization

But, that has some conflicts with hash. Not sure of a good
syntax. The problem is we can't apply methods directly to
blocks - you have to convert to Proc, apply the method, and
convert back.

···

--- Florian Groß <florgro@gmail.com> wrote:

Yukihiro Matsumoto wrote:

> >i'm trying to be able to define a proc that can be called
in the context of
> >self, eg:
> >
> > block = lambda{ p 42 }
> > an_obj.instance_eval &block
> >
> >but which can also be called with arguments, for example
(imaginary ruby):
>
> I understand what you want. But I haven't come up with a
good name
> for the function yet.

What about Proc#with_self() that will return a new proc
similar to the
current one, but with a changed self context?

__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around

^^^
                                                        ^^^

lol! :wink:

-a

···

On Tue, 20 Sep 2005, Robert Klemme wrote:

Hacky but nice! For thread safety how about:

  class Object
    def arg_instance_eval( *args, &block )
      c = class << self; self; end
      meth = "__m_#{Thread.current.object_id}_#{rand 666}"

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

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

<snip>

what i think to be the final version:

   class Object
     def evaluate(*a, &b)
       ret, sent = nil
       loop do
         m = "____evaluate____#{ Thread::current.object_id }____#{ rand 666 }____#{ rand 42 }____"
         klass = Class === self ? self : self::class
         begin
           klass.module_eval{ define_method m, &b }
           ret = send(sent = m, *a)
         ensure
           begin
             klass.module_eval{ remove_method m }
           ensure
             break if sent
           end
         end
       end
       ret
     end
   end

   class C
     def y
       42
     end
   end

   b = lambda{|x| p [x, y, self]}

   c = C::new
   x = 42
   c.evaluate(x, &b) #=> [42, 42, #<C:0xb7f2f5c0>]

-a

···

On Tue, 20 Sep 2005, Robert Klemme wrote:

Hacky but nice! For thread safety how about:

--

email :: ara [dot] t [dot] howard [at] noaa [dot] gov
phone :: 303.497.6469
Your life dwells amoung the causes of death
Like a lamp standing in a strong breeze. --Nagarjuna

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

proc.bound_to(object), perhaps.

martin

···

Florian Groß <florgro@gmail.com> wrote:

Procs are currently immutable and I'd assume that the source code
assumes that they can not be changed in several places. It's less risky
to return a new object with a changed self context, IMHO.