# Block equality

**URL:** <https://www.ruby-forum.com/t/block-equality/65073>\
**Category:** Ruby\
**Created:** [August 15, 2006, 11:24pm UTC](https://www.ruby-forum.com/t/block-equality/65073 "2006-08-15T23:24:53Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 15, 2006, 11:24pm UTC](https://www.ruby-forum.com/t/block-equality/65073/1 "2006-08-15T23:24:53Z")

</div>

Is there a way to compare two blocks with each other?

If you promote a block into a Proc, how would you know that the  
original block was the same?

This is what I want to do

(1…10).each do  
once { puts “Hi Tom”}  
end

I’ve tried to implement once like this

class \<\< self  
def once(&block)  
@ids ||= {}  
block.call unless @ids.key? block.object\_id  
@ids[block.object\_id] = :true  
puts @ids.keys.join(’, ')  
end  
end

I’ve even tried a varient using == and ===

def l(&b)  
@t ||= b  
puts b == @t  
puts b === @t  
@t = b  
end

(1…2).each { l{x=1} }

output:  
true  
true  
false  
false

How can you compare two procs that have the same body?

Thanks,  
– Tom.

–  
“Nothing will ever be attempted, if all  
possible objections must first be  
overcome.” - Samuel Johnson

“Luck is what happens when  
preparation meets opportunity.” - Seneca

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 15, 2006, 11:27pm UTC](https://www.ruby-forum.com/t/block-equality/65073/2 "2006-08-15T23:27:53Z")

</div>

ruby version:

ruby 1.8.4 (2006-04-14) [i386-mswin32]

On 8/15/06, Tom J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> –  
> “Nothing will ever be attempted, if all  
> possible objections must first be  
> overcome.” - Samuel Johnson
> 
> “Luck is what happens when  
> preparation meets opportunity.” - Seneca

–  
“Nothing will ever be attempted, if all  
possible objections must first be  
overcome.” - Samuel Johnson

“Luck is what happens when  
preparation meets opportunity.” - Seneca

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 16, 2006, 12:16am UTC](https://www.ruby-forum.com/t/block-equality/65073/3 "2006-08-16T00:16:01Z")

</div>

Marshall T. Vandegrift wrote:

> a block to a Proc via &block in the argument list results in a new  
> Proc each time and (b) ruby 1.8 provides no introspection into the  
> actual contents of a block.

Yes, it’s kind of like asking if two equations or two methods are equal.  
On the other hand, you could probably use the SerializeableProc  
(developed here: [Ruby Quiz - SerializableProc (#38)](http://rubyquiz.com/quiz38.html)), add an equality  
method, and then you’d have it. 🙂

-Justin

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 16, 2006, 12:10am UTC](https://www.ruby-forum.com/t/block-equality/65073/4 "2006-08-16T00:10:00Z")

</div>

“Tom J.” [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) writes:

> Is there a way to compare two blocks with each other?
> 
> If you promote a block into a Proc, how would you know that the  
> original block was the same?

I haven’t dived into the code, but I’m pretty sure that (a) promoting  
a block to a Proc via &block in the argument list results in a new  
Proc each time and (b) ruby 1.8 provides no introspection into the  
actual contents of a block.

> This is what I want to do

This struck me as interesting, so here’s one possible solution:

```
class Object
  module OnceHelper; end

  def once
    execute = false
    vname = '_' << (begin; raise; rescue; $!.backtrace[1]; end).
      split(':')[0..1].join('_').gsub(/[^A-Za-z0-9]/, '_')

    begin
      critical, Thread.critical = Thread.critical, true
      execute = !OnceHelper.instance_variables.include?("@#{vname}")
      OnceHelper.instance_variable_set("@#{vname}", true)
    ensure
      Thread.critical = critical
    end

    yield if execute
  end
end

class OnceDoer
  def try_once
    once { "just this once!" }
  end
end

doer1 = OnceDoer.new
p doer1.try_once
p doer1.try_once

doer2 = OnceDoer.new
p doer2.try_once
p doer2.try_once

# >> "just this once!"
# >> nil
# >> nil
# >> nil

```

N.B. that with this solution a ‘once’ block is truly executed only  
once ever, even across separate instances. If you instead squirrel  
the generated instance variables away in the individual object  
instance the block will only execute once per instance.

Hope this helps.

-Marshall

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 16, 2006, 7:03pm UTC](https://www.ruby-forum.com/t/block-equality/65073/5 "2006-08-16T19:03:33Z")

</div>

Tom J. wrote:

> > > > original block was the same?  
> > > > Yes, it’s kind of like asking if two equations or two methods are equal.
> 
> Thanks,  
> – Tom.  
> Hi Tom,

Well, I did find one instance where this works. If you use Proc#dup or  
Proc#clone, you will end up with a new Proc object, but they will  
evaluate to being equal:

irb(main):001:0\> a = Proc.new { n = 1 }  
=\> #Proc:0xb7d36224@:1(irb)  
irb(main):002:0\> b = a.dup  
=\> #Proc:0xb7d36224@:1(irb)  
irb(main):003:0\> a.object\_id  
=\> -605441814  
irb(main):004:0\> b.object\_id  
=\> -605445814  
irb(main):005:0\> a == b  
=\> true  
irb(main):006:0\> b == a  
=\> true  
irb(main):007:0\> c = Proc.new { n = 1 }  
=\> #Proc:0xb7d27ecc@:7(irb)  
irb(main):008:0\> d = c.clone  
=\> #Proc:0xb7d27ecc@:7(irb)  
irb(main):009:0\> c.object\_id  
=\> -605470914  
irb(main):010:0\> d.object\_id  
=\> -605475424  
irb(main):011:0\> c == d  
=\> true  
irb(main):012:0\> d == c  
=\> true

Other than that, I don’t see a way for two Procs to have the same block  
(and know it). Take a look at the source for Proc#==, it’s somewhat  
helpful as well.

I realize this doesn’t help you in the general case, though…

-Justin

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 16, 2006, 5:23pm UTC](https://www.ruby-forum.com/t/block-equality/65073/6 "2006-08-16T17:23:49Z")

</div>

On 8/15/06, Justin C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > >
> 
> On the other hand, you could probably use the SerializeableProc  
> (developed here: [Ruby Quiz - SerializableProc (#38)](http://rubyquiz.com/quiz38.html)), add an equality  
> method, and then you’d have it. 🙂

Thanks Marshall and Justin.

This [class Proc - RDoc Documentation](http://ruby-doc.org/core/classes/Proc.html#M001161)

“Return true if prc is the same object as other\_proc, or if they are  
both procs with the same body.”

led me to believe that Procs would evaluate to equality if they had  
the same body.

So I would have expected that the following:

s = lambda { x = 1 }  
t = lambda { x = 1 }  
s == t # =\> true expected, false in reality

So my question is; when would the body of Procs ever be the same?

Thanks,  
– Tom.

–  
“Nothing will ever be attempted, if all  
possible objections must first be  
overcome.” - Samuel Johnson

“Luck is what happens when  
preparation meets opportunity.” - Seneca

---

<div class="post-metadata">

**Author:** ![tomjerry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/7bcc69/32.png) [@tomjerry](https://www.ruby-forum.com/u/tomjerry)\
**Post date:** [August 16, 2006, 7:57pm UTC](https://www.ruby-forum.com/t/block-equality/65073/7 "2006-08-16T19:57:39Z")

</div>

Hi,

On Wed, 16 Aug 2006 17:21:39 +0200, Tom J. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> s = lambda { x = 1 }  
> t = lambda { x = 1 }  
> s == t # =\> true expected, false in reality

If you really want to check if procs have the same or equivalent bodies,  
you can use RubyNode ([http://rubynode.rubyforge.org/](http://rubynode.rubyforge.org/)):

> > p1 = proc { 1 + 1 }  
> > =\> #Proc:0xb7a70b64@:1(irb)  
> > p2 = proc { 1 + 1 }  
> > =\> #Proc:0xb7a6e580@:2(irb)  
> > require “rubynode”  
> > =\> true  
> > p1.body\_node.transform  
> > =\> [:call, {:args=\>[:array, [[:lit, {:lit=\>1}]]], :mid=\>:+,  
> > :recv=\>[:lit,  
> > {:lit=\>1}]}]  
> > p1.body\_node.transform == p2.body\_node.transform  
> > =\> true  
> > p1 == p2  
> > =\> false

But please be aware that the equality of the body node does not imply  
that  
the blocks have the same closure:

> > def foo(a) proc { a } end  
> > =\> nil  
> > p1 = foo(1)  
> > =\> #Proc:0xb7a6217c@:8(irb)  
> > p2 = foo(2)  
> > =\> #Proc:0xb7a6217c@:8(irb)  
> > p1.body\_node.transform == p2.body\_node.transform  
> > =\> true  
> > p1[]  
> > =\> 1  
> > p2[]  
> > =\> 2

And it is also possible that different Ruby code parses to the same node  
tree:

> > p1 = proc { if 1 then 2 else 3 end }  
> > =\> #Proc:0xb7ac83b4@:17(irb)  
> > p2 = proc { unless 1 then 3 else 2 end }  
> > =\> #Proc:0xb7ac239c@:18(irb)  
> > p3 = proc { 1 ? 2 : 3 }  
> > =\> #Proc:0xb7abec4c@:19(irb)  
> > p1.body\_node.transform == p2.body\_node.transform  
> > =\> true  
> > p1.body\_node.transform == p3.body\_node.transform  
> > =\> true  
> > p2.body\_node.transform == p3.body\_node.transform  
> > =\> true  
> > p1.body\_node.transform  
> > =\> [:if, {:else=\>[:lit, {:lit=\>3}], :cond=\>[:lit, {:lit=\>1}],  
> > :body=\>[:lit, {:lit=\>2}]}]

So this is probably not very useful for your once method, but  
interesting  
anyway.

Dominik
