Closures in Ruby
More than 1 Type of Anonymous Function
For all it’s simplicity, sometimes Ruby complicates things a bit.
Ruby has 3 structures for the anonymous functions concept. Let’s break them down into laymen’s terms and demystify with examples:
Block
- an anonymous function that’s passed to a method. It cannot be stored into a variable or executed by itself
# Execute a given block _before_ Taylor Swift's Award Ceremony
def interrupt(block)
yield
puts '<Taylor Swift\'s award ceremony>'
end
interrupt do
puts 'Imma let you finish but Beyonce had the best...'
end
=> 'Imma let you finish but Beyonce had the best...'
=> '<Taylor Swift\'s award ceremony>'
Ok, this is going to look really funky at first. But try replacing the Ruby specific keyword block with an anonymous function and replace yield with our regular PHP syntax. You’ll see it’s actually very similar to PHP once it’s broken down:
Proc
- a Ruby anonymous function that is actually an object and can be stored in a variable or executed immediately:
anonymous_function = Proc.new { puts 'I\'m a strong, independent function who don\'t need no wrapper Class to get stuff done.' }
anonymous_function.call
=> 'I\'m a strong, independent function who don\'t need no wrapper Class to get stuff done.'
And that’s really the big difference between Procs and Blocks. Blocks can’t live on their own outside of a method, but Procs can.
Just for fun, here’s the same idea in PHP:
Since you don’t execute methods with with paranthesis in Ruby, they have a reserved method name for Closures called call that is the designated ().
Lamda
- A Ruby anonymous function that’s basically a Proc, but with 2 very minor twists:
1) Lambdas actually check for the number of arguments expected, whereas Procs don’t really care
doesnt_care = Proc.new { |something| puts something }
# notice that we didn't give `call` any argument what-so-ever here
# but it still chugs along and doesn't throw an Exception
doesnt_care.call
=> nil
A Lambda is like the one friend who’s taking their Jimmy John’s sandwich back because they asked for pickles but didn’t get any:
does_absolutely_care = Proc.new { |something| puts something }
# Again, no arguments but Lambdas care A LOT.
does_absolutely_care.call
=> ArgumentError: wrong number of arguments (0 for 1)
2) Lambdas can actually return inside of themselves whereas Procs only return outside of themselves
What? I know I know, it’s confusing wording. However it’s actually not that complicated at all. returning inside of a PHP or Javascript function normally ends the function and returns the result. In Ruby, Lamdas exact exactly like that:
def journey
puts 'Oh oh, we\'re halfway there'
next_lyric = Lambda.new do
puts 'We\'re living on a prayer!'
return # <- Notice this little `return` right here. Very important.
end
next_lyric.call
puts 'Take my hand, we\'ll make it swear!'
end
journey
=> 'Oh oh, we\'re halfway there'
=> 'We\'re living on a prayer!'
=> 'Take my hand, we\'ll make it swear!'
In our example, after our little Lambda named next_lyric
finshed up it’s job and return’d then execution continued in our lovely journey
function and it spit out all of the lyrics. Awesome.
On the other hand, Procs do something very different with returning:
def journey
puts 'Oh oh, we\'re halfway there'
next_lyric = Proc.new do
puts 'We\'re living on a prayer!'
return # <- Notice this little `return` right here. Very important.
end
next_lyric.call
puts 'Take my hand, we\'ll make it swear!'
end
journey
=> 'Oh oh, we\'re halfway there'
=> 'We\'re living on a prayer!'
The only difference here is I made next_lyric
powered by a Proc instead of Lambda, and it stopped the execution of the outside journey
function. Even though the next stanza is inside of the function, it will never ever be sung despite calling journey over and over and over again.
So close, yet so far.
In closing, there are 2 minor differences between Lambas and Procs. If these details are overwhelming, don’t worry. These are tiny nuansces, don’t let them stop you from finishing your journey on becoming a Ruby developer.