help with tricky proc/binding issue

Discussion in 'Ruby' started by Ara.T.Howard, Sep 19, 2005.

  1. Ara.T.Howard

    Ara.T.Howard Guest

    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
    ===============================================================================
     
    Ara.T.Howard, Sep 19, 2005
    #1
    1. Advertising

  2. Hi,

    In message "Re: help with tricky proc/binding issue"
    on Mon, 19 Sep 2005 23:42:12 +0900, "Ara.T.Howard" <> 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.
     
    Yukihiro Matsumoto, Sep 19, 2005
    #2
    1. Advertising

  3. 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
     
    Robert Klemme, Sep 19, 2005
    #3
  4. Ara.T.Howard

    Ara.T.Howard Guest

    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" <> 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.


    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
    --
    ===============================================================================
    | 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, Sep 19, 2005
    #4
  5. Ara.T.Howard

    Pit Capitain Guest

    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
     
    Pit Capitain, Sep 19, 2005
    #5
  6. 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...
     
    Florian Groß, Sep 19, 2005
    #6
  7. 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?
     
    Florian Groß, Sep 19, 2005
    #7
  8. 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.
     
    Florian Groß, Sep 19, 2005
    #8
  9. 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
     
    Robert Klemme, Sep 19, 2005
    #9
  10. Florian Groß <> 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.


    proc.bound_to(object), perhaps.

    martin
     
    Martin DeMello, Sep 19, 2005
    #10
  11. Ara.T.Howard

    Ara.T.Howard Guest

    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]


    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
    --
    ===============================================================================
    | 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, Sep 19, 2005
    #11
  12. Ara.T.Howard

    Ara.T.Howard Guest

    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}"

    ^^^
    ^^^
    ^^^

    lol! ;-)

    -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
    ===============================================================================
     
    Ara.T.Howard, Sep 19, 2005
    #12
  13. Ara.T.Howard

    Ara.T.Howard Guest

    On Tue, 20 Sep 2005, Robert Klemme wrote:

    > Hacky but nice! For thread safety how about:

    <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
    --
    ===============================================================================
    | 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, Sep 19, 2005
    #13
  14. Ara.T.Howard

    Eric Mahurin Guest

    --- Florian Gro=DF <> wrote:

    > Yukihiro Matsumoto wrote:
    >=20
    > > |i'm trying to be able to define a proc that can be called

    > in the context of
    > > |self, eg:
    > > |
    > > | block =3D lambda{ p 42 }
    > > | an_obj.instance_eval &block
    > > |
    > > |but which can also be called with arguments, for example

    > (imaginary ruby):
    > >=20
    > > I understand what you want. But I haven't come up with a

    > good name
    > > for the function yet.

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


    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.


    __________________________________________________
    Do You Yahoo!?
    Tired of spam? Yahoo! Mail has the best spam protection around=20
    http://mail.yahoo.com=20
     
    Eric Mahurin, Sep 19, 2005
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. David Lozzi
    Replies:
    3
    Views:
    1,940
    David Lozzi
    Jun 1, 2005
  2. NevilleDNZ
    Replies:
    9
    Views:
    448
    NevilleDNZ
    Aug 16, 2006
  3. Replies:
    9
    Views:
    538
    CBFalconer
    Apr 25, 2006
  4. Jean-Hugues ROBERT

    Why no Proc##[]=() ? Why no Proc##replace() ?

    Jean-Hugues ROBERT, May 1, 2004, in forum: Ruby
    Replies:
    14
    Views:
    293
    Jean-Hugues ROBERT
    May 5, 2004
  5. Minkoo Seo

    Proc vs lambda vs proc

    Minkoo Seo, Feb 4, 2007, in forum: Ruby
    Replies:
    19
    Views:
    246
    Brian Candler
    Feb 6, 2007
Loading...

Share This Page