[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

What is Proc#==

Sylvain Joyeux

2/12/2007 11:45:00 AM

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

9 Answers

Kalman Noel

2/12/2007 1:11:00 PM

0

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

George

2/13/2007 3:00:00 AM

0

Hi Kalman, Sylvain, list,

On 2/13/07, Kalman Noel <invalid@gmx.net> 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.

Marcello Barnaba

2/13/2007 3:13:00 AM

0

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:
>
>   lambda{} == lambda{}  #=> true
>
> As opposed to:
>
>   lambda{nil} == lambda{nil}  #=> false


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

>> lambda{}
=> #<Proc:0x00000000@(irb):46>

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?
--
pub 1024D/8D2787EF 723C 7CA3 3C19 2ACE 6E20 9CC1 9956 EB3C 8D27 87EF

Edwin Fine

2/13/2007 6:25:00 AM

0

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

Edwin Fine

2/13/2007 6:29:00 AM

0

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

Marcello Barnaba

2/13/2007 6:28:00 PM

0

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

Gary Wright

2/13/2007 8:07:00 PM

0


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

George

2/14/2007 1:42:00 AM

0

On 2/13/07, Edwin Fine <efine145-nospam01@usa.net> 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

2/14/2007 1:47:00 AM

0

On 2/13/07, Marcello Barnaba <bofh@softmedia.info> 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.