Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > What is Proc#==

Reply
Thread Tools

What is Proc#==

 
 
Sylvain Joyeux
Guest
Posts: n/a
 
      02-12-2007
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

 
Reply With Quote
 
 
 
 
Kalman Noel
Guest
Posts: n/a
 
      02-12-2007
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
 
Reply With Quote
 
 
 
 
George Ogata
Guest
Posts: n/a
 
      02-13-2007
Hi Kalman, Sylvain, list,

On 2/13/07, Kalman Noel <(E-Mail Removed)> 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.

 
Reply With Quote
 
Marcello Barnaba
Guest
Posts: n/a
 
      02-13-2007
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

 
Reply With Quote
 
Edwin Fine
Guest
Posts: n/a
 
      02-13-2007
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/.

 
Reply With Quote
 
Edwin Fine
Guest
Posts: n/a
 
      02-13-2007
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/.

 
Reply With Quote
 
Marcello Barnaba
Guest
Posts: n/a
 
      02-13-2007
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

 
Reply With Quote
 
Gary Wright
Guest
Posts: n/a
 
      02-13-2007

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

 
Reply With Quote
 
George Ogata
Guest
Posts: n/a
 
      02-14-2007
On 2/13/07, Edwin Fine <(E-Mail Removed)> 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.

 
Reply With Quote
 
George Ogata
Guest
Posts: n/a
 
      02-14-2007
On 2/13/07, Marcello Barnaba <(E-Mail Removed)> 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.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off




Advertisments