What is Proc#==

Discussion in 'Ruby' started by Sylvain Joyeux, Feb 12, 2007.

  1. From the description,
    ---------------------------------------------------------------- Proc#==
    prc == other_proc => true or false
    ------------------------------------------------------------------------
    Return true if prc is the same object as other_proc, or if they
    are both procs with the same body.

    I thought that a == b in
    =============================================
    def block_to_proc(&prc)
    prc
    end
    def test
    block_to_proc do
    end
    end

    a = test
    b = test
    =============================================
    a == b (since both proc have the same body)

    However, it returns false. So, the obvious question is: what does "if they
    are both procs with the same body" mean ?
    --
    Sylvain Joyeux
     
    Sylvain Joyeux, Feb 12, 2007
    #1
    1. Advertising

  2. Sylvain Joyeux

    Kalman Noel Guest

    Sylvain Joyeux:
    > From the description,
    > ---------------------------------------------------------------- Proc#==
    > prc == other_proc => true or false
    > ------------------------------------------------------------------------
    > Return true if prc is the same object as other_proc, or if they
    > are both procs with the same body.
    >
    > I thought that a == b in
    > =============================================
    > def block_to_proc(&prc)
    > prc
    > end
    > def test
    > block_to_proc do
    > end
    > end
    >
    > a = test
    > b = test


    My guess would be that a and b were created in different contexts, and
    that this is why they are not equal. The problem about that is that thay
    aren't really created in different contexts here. They are in this case,
    however:

    def test(arg)
    block_to_proc { arg }
    end

    a = test(1)
    b = test(2)

    Obviously a and b are not equal here, because a.call and b.call are not
    equal. Note, also:

    x = 3
    lambda { } == lambda { } # => true
    lambda { x } == lambda { x } # => false (maybe because x may have changed
    in between)

    Still the behavior you described seems like a bug to me, because of
    lambda { } == lambda { }. But I may not see the existing reason why it
    isn't.

    Kalman
     
    Kalman Noel, Feb 12, 2007
    #2
    1. Advertising

  3. Sylvain Joyeux

    George Ogata Guest

    Hi Kalman, Sylvain, list,

    On 2/13/07, Kalman Noel <> wrote:
    > Sylvain Joyeux:
    > > From the description,
    > > ---------------------------------------------------------------- Proc#==
    > > prc == other_proc => true or false
    > > ------------------------------------------------------------------------
    > > Return true if prc is the same object as other_proc, or if they
    > > are both procs with the same body.
    > >
    > > I thought that a == b in
    > > =============================================
    > > def block_to_proc(&prc)
    > > prc
    > > end
    > > def test
    > > block_to_proc do
    > > end
    > > end
    > >
    > > a = test
    > > b = test

    >
    > My guess would be that a and b were created in different contexts, and
    > that this is why they are not equal. The problem about that is that thay
    > aren't really created in different contexts here. They are in this case,
    > however:
    >
    > def test(arg)
    > block_to_proc { arg }
    > end
    >
    > a = test(1)
    > b = test(2)
    >
    > Obviously a and b are not equal here, because a.call and b.call are not
    > equal. Note, also:
    >
    > x = 3
    > lambda { } == lambda { } # => true
    > lambda { x } == lambda { x } # => false (maybe because x may have changed
    > in between)


    Actually, since blocks are closures, the x is the same variable in
    that line. If the next line was x = 5, then the x in both would be
    updated. (Well, unless those blocks had been GC'ed by then... ;-)

    > Still the behavior you described seems like a bug to me, because of
    > lambda { } == lambda { }. But I may not see the existing reason why it
    > isn't.


    I believe the "same body" part means that the body was constructed
    from the same block. e.g.:

    body = lambda{1+2}
    lambda(&body) == lambda(&body) #=> true

    Or:

    def foo
    Proc.new == Proc.new
    end
    foo{1+2} #=> true

    There is one exception: empty procs are the "same" no matter how
    they're constructed:

    lambda{} == lambda{} #=> true

    As opposed to:

    lambda{nil} == lambda{nil} #=> false

    I agree that the rdoc is a little misleading. Perhaps an example should follow.

    Regards,
    George.
     
    George Ogata, Feb 13, 2007
    #3
  4. Hi,

    On Tuesday 13 February 2007 03:59, George Ogata wrote:
    > There is one exception: empty procs are the "same" no matter how
    > they're constructed:
    >
    > =A0 lambda{} =3D=3D lambda{} =A0#=3D> true
    >
    > As opposed to:
    >
    > =A0 lambda{nil} =3D=3D lambda{nil} =A0#=3D> false



    it is worth noting the "address" of the empty proc being 0 (NULL? :)

    >> lambda{}

    =3D> #<Proc:0x00000000@(irb):46>

    but I do not understand why:
    >> [lambda{}.object_id, lambda{}.object_id]

    =3D> [-606913178, -606913188]

    and:
    >> lambda{} =3D=3D=3D lambda{}

    =3D> true

    ? rdoc says that Proc uses Module's =3D=3D=3D, shouldn't that check for o=
    bject=20
    identity? what's going on?
    --=20
    pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF
     
    Marcello Barnaba, Feb 13, 2007
    #4
  5. Sylvain Joyeux

    Edwin Fine Guest

    Here's the C code for proc_eq (in eval.c). It seems that the procs have
    to either be the same object, or failing that have the same type
    (T_DATA), class, body, variables, scope, in-block local variables
    (dyna_vars), and flags.

    static VALUE
    proc_eq(self, other)
    VALUE self, other;
    {
    struct BLOCK *data, *data2;

    if (self == other) return Qtrue;
    if (TYPE(other) != T_DATA) return Qfalse;
    if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse;
    if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
    Data_Get_Struct(self, struct BLOCK, data);
    Data_Get_Struct(other, struct BLOCK, data2);
    if (data->body != data2->body) return Qfalse;
    if (data->var != data2->var) return Qfalse;
    if (data->scope != data2->scope) return Qfalse;
    if (data->dyna_vars != data2->dyna_vars) return Qfalse;
    if (data->flags != data2->flags) return Qfalse;

    return Qtrue;
    }

    The only way so far that I have been able to create two equal procs that
    have different object IDs is to clone or dup them. I am sure there must
    be another way using some metaprogramming, but I am not experienced
    enough in Ruby to find it easily (or maybe ever:)

    irb(main):001:0> a = lambda { 4 }
    => #<Proc:0x00002b8dd669e828@(irb):1>
    irb(main):002:0> b = a.clone
    => #<Proc:0x00002b8dd669e828@(irb):1>
    irb(main):003:0> a.object_id
    => 23944093823940
    irb(main):004:0> b.object_id
    => 23944093815980
    irb(main):005:0> a == b
    => true


    --
    Posted via http://www.ruby-forum.com/.
     
    Edwin Fine, Feb 13, 2007
    #5
  6. Sylvain Joyeux

    Edwin Fine Guest

    Incidentally, the reason why lambda {} == lambda {} may be because all
    the values I showed in the previous post (e.g. data->body, data->var,
    etc) are all zero or NULL (no vars, no body, and so on) which would make
    them equal and therefore the procs equal.

    Maybe.

    --
    Posted via http://www.ruby-forum.com/.
     
    Edwin Fine, Feb 13, 2007
    #6
  7. Hi,

    On Tuesday 13 February 2007 07:29, Edwin Fine wrote:
    > Incidentally, the reason why lambda {} == lambda {} may be because all
    > the values I showed in the previous post (e.g. data->body, data->var,
    > etc) are all zero or NULL (no vars, no body, and so on) which would make
    > them equal and therefore the procs equal.


    Thank you for your insight! It's clear now. /me has to remember to always take
    a look at the source. :).

    --
    pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF
     
    Marcello Barnaba, Feb 13, 2007
    #7
  8. Sylvain Joyeux

    Gary Wright Guest

    On Feb 13, 2007, at 1:24 AM, Edwin Fine wrote:
    > The only way so far that I have been able to create two equal procs
    > that
    > have different object IDs is to clone or dup them.


    Here are a few other ways that seem to be analogous to clone/dup
    but via other mechanisms:

    a = lambda { 4 }
    b = lambda &a
    c = proc &b
    d = Proc.new &c

    def the_block(&block); block; end

    e = the_block &d

    p a == b # true
    p b == c # true
    p c == d # true
    p d == e # true

    This shows that the 'equality' of a lambda proc doesn't get altered via
    Kernel#lambda, Kernel#proc, Proc.new, or block argument passing.

    But look at:

    proc1 = Proc.new { 4 }
    lambda1 = lambda &proc1
    p proc1 == lambda1 # false

    This shows that Kernel#lambda constructs procs that have different
    equality semantics than procs from Proc.new.

    Gary Wright
     
    Gary Wright, Feb 13, 2007
    #8
  9. Sylvain Joyeux

    George Ogata Guest

    On 2/13/07, Edwin Fine <> wrote:
    > Here's the C code for proc_eq (in eval.c). It seems that the procs have
    > to either be the same object, or failing that have the same type
    > (T_DATA), class, body, variables, scope, in-block local variables
    > (dyna_vars), and flags.
    >
    > static VALUE
    > proc_eq(self, other)
    > VALUE self, other;
    > {
    > struct BLOCK *data, *data2;
    >
    > if (self == other) return Qtrue;
    > if (TYPE(other) != T_DATA) return Qfalse;
    > if (RDATA(other)->dmark != (RUBY_DATA_FUNC)blk_mark) return Qfalse;
    > if (CLASS_OF(self) != CLASS_OF(other)) return Qfalse;
    > Data_Get_Struct(self, struct BLOCK, data);
    > Data_Get_Struct(other, struct BLOCK, data2);
    > if (data->body != data2->body) return Qfalse;
    > if (data->var != data2->var) return Qfalse;
    > if (data->scope != data2->scope) return Qfalse;
    > if (data->dyna_vars != data2->dyna_vars) return Qfalse;
    > if (data->flags != data2->flags) return Qfalse;
    >
    > return Qtrue;
    > }


    Hmm, so my earlier comment about empty blocks was wrong. You can
    actually have unequal empty blocks if you define them in different
    contexts...:

    def foo(x)
    lambda{}
    end

    lambda{} == foo(1) #=> false

    ... or with different flags. The return semantics (Proc.new vs.
    lambda) is stored as a flag, hence (as Gary noted):

    Proc.new{} == lambda{} #=> false

    As you pointed out in your other post, body, vars, and dyna_vars seem
    to be NULL for empty blocks.

    Regards,
    George.
     
    George Ogata, Feb 14, 2007
    #9
  10. Sylvain Joyeux

    George Ogata Guest

    On 2/13/07, Marcello Barnaba <> wrote:

    > but I do not understand why:
    > >> [lambda{}.object_id, lambda{}.object_id]

    > => [-606913178, -606913188]
    >
    > and:
    > >> lambda{} === lambda{}

    > => true
    >
    > ? rdoc says that Proc uses Module's ===, shouldn't that check for object
    > identity? what's going on?


    Hmm, where does it say that? Module#===(obj) checks that
    obj.is_a?(self), not obj.equal?(self), which doesn't really make sense
    to me for Proc objects.

    Looks like Proc#=== falls back to Object#===, which in turn calls #==,
    i.e., Proc#==. Whee!

    Regards,
    George.
     
    George Ogata, Feb 14, 2007
    #10
    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. Kishor

    Dynamic Execution of Function/Proc

    Kishor, Sep 24, 2003, in forum: ASP .Net
    Replies:
    9
    Views:
    550
    Kishor
    Sep 27, 2003
  2. David Lozzi
    Replies:
    3
    Views:
    1,943
    David Lozzi
    Jun 1, 2005
  3. NevilleDNZ
    Replies:
    9
    Views:
    449
    NevilleDNZ
    Aug 16, 2006
  4. Jean-Hugues ROBERT

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

    Jean-Hugues ROBERT, May 1, 2004, in forum: Ruby
    Replies:
    14
    Views:
    294
    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:
    247
    Brian Candler
    Feb 6, 2007
Loading...

Share This Page