As we all know, there are 2 main differences between procs and lambdas in Ruby.
1. Argument checking:
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
<span class='line'><span class="o">>></span> <span class="nb">p</span> <span class="o">=</span> <span class="no">Proc</span><span class="o">.</span><span class="n">new</span> <span class="p">{</span> <span class="o">|</span><span class="nb">name</span><span class="o">|</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="c1">#<Proc:0x000001008dc600@(irb):3></span>
</span><span class='line'><span class="o">>></span> <span class="n">l</span> <span class="o">=</span> <span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="nb">name</span><span class="o">|</span> <span class="s2">"Hello </span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span>
</span><span class='line'><span class="o">=></span> <span class="c1">#<Proc:0x000001008d3c08@(irb):4 (lambda)></span>
</span><span class='line'><span class="o">>></span> <span class="nb">p</span><span class="o">.</span><span class="n">call</span>
</span><span class='line'><span class="o">=></span> <span class="s2">"Hello "</span>
</span><span class='line'><span class="o">>></span> <span class="n">l</span><span class="o">.</span><span class="n">call</span>
</span><span class='line'><span class="no">ArgumentError</span><span class="p">:</span> <span class="n">wrong</span> <span class="n">number</span> <span class="n">of</span> <span class="n">arguments</span> <span class="p">(</span><span class="mi">0</span> <span class="k">for</span> <span class="mi">1</span><span class="p">)</span>
</span><span class='line'> <span class="n">from</span> <span class="p">(</span><span class="n">irb</span><span class="p">):</span><span class="mi">4</span><span class="ss">:in</span> <span class="sb">`block in irb_binding'</span>
</span><span class='line'><span class="sb"> from (irb):6:in `</span><span class="n">call</span><span class="s1">'</span>
</span><span class='line'><span class="s1"> from (irb):6</span>
</span><span class='line'><span class="s1"> from /Users/michi/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'</span>
</span>
2. The possibility to return from within the closure:
1
2
3
4
5
6
7
8
9
10
11
12
>> p = Proc . new { return }
=> #<Proc:0x000001008c83a8@(irb):7>
>> l = lambda { return }
=> #<Proc:0x000001008c4050@(irb):8 (lambda)>
>> p . call
LocalJumpError : unexpected return
from ( irb ): 7 :in `block in irb_binding'
from (irb):9:in ` call '
from (irb):9
from /Users/michi/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'
>> l . call
=> nil
I’ve known about this for a while, but as a Rubyists who until quite recently happily ignored Rails, I didn’t know that ActiveSupport changes the “LocalJumpError” from the second example into
1
2
3
1
2
3
<span class='line'><span class="sb">`call': Cannot yield from a Proc type filter.</span>
</span><span class='line'><span class="sb"> The Proc must take two arguments and execute</span>
</span><span class='line'><span class="sb"> #call on the second argument. (ArgumentError)</span>
</span>
when you try to return from callbacks like “before_save”. I spent quite some time debugging this before I finally found the solution in this blog post . Instead of
1
2
3
4
1
2
3
4
<span class='line'><span class="n">after_save</span> <span class="k">do</span> <span class="o">|</span><span class="n">foo</span><span class="o">|</span>
</span><span class='line'> <span class="k">return</span> <span class="k">if</span> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'><span class="k">end</span>
</span>
you have to do
1
2
3
4
1
2
3
4
<span class='line'><span class="n">after_save</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">foo</span><span class="o">|</span>
</span><span class='line'> <span class="k">return</span> <span class="k">if</span><span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'><span class="p">})</span>
</span>
Probably obvious to more experienced Rails developers, but I really got thrown off by the “ArgumentError” that replaced the “LocalJumpError”.