Skip to content

Instantly share code, notes, and snippets.

@mislav
Last active March 26, 2021 18:34
Show Gist options
  • Star 67 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save mislav/4508988 to your computer and use it in GitHub Desktop.
Save mislav/4508988 to your computer and use it in GitHub Desktop.
Jim Weirich on the differences between procs and lambdas in Ruby

Jim Weirich:

This is how I explain it… Ruby has Procs and Lambdas. Procs are created with Proc.new { }, lambdas are created with lambda {} and ->() {}.

In Ruby 1.8, proc {} creates lambda, and Ruby 1.9 it creates procs (don't ask).

Lambdas use method semantics when handling parameters, procs use assignment semantics when handling parameters.

This means lambdas, like methods, will raise an ArgumentError when called with fewer arguments than they were defined with. Procs will simply assign nil to variables for arguments that were not passed in.

Starting from Ruby 1.9, both procs and lambdas—like methods—support defining arguments with default values. To lambdas, such arguments are then optional at call time.

Lambdas act like anonymous functions w.r.t. the return statement (i.e. return will return from the lambda). Procs are invisible to return, so a return statement will return from the enclosing function. The technical way to say this is that Procs follow the Tennent Correspondence Principle w.r.t. return statements. This allows you to wrap some code in a proc and immediately call the proc without changing the semantics of the code.

That leaves blocks. Blocks don't actually exist as things manipulated by the Ruby language. When I talk about blocks, I am referring to the syntactical construct of putting do/end or {} after a method invocation. When you write code with this syntactical construction, Ruby arranges for the code in the block to be passed to method being called. MRI will create a proc object representing the block only if you reference the block with a &block parameter in the calling sequence. This is a mere implementation detail.

Gary Bernhardt:

A: “Everything is an object in Ruby! :D”
B: “What is the class of a block?”
A: “:-[”

@bloudermilk
Copy link

Very concise. Thank you for sharing!

@bayendor
Copy link

Yes, thank you. That helped to solve an issue I had with "Episode 5. Fundamentals of Ruby - Internals - Procs & Lamdas." The code example did not behave as it did in the video, and the difference was the Ruby version.

@bf4
Copy link

bf4 commented Jul 25, 2013

re:

http://innig.net/software/ruby/closures-in-ruby

Jim Weirich 2013-07-25:

His analysis seems a bit over-complicated to me, at least for modern Ruby. As far as I can tell, there are only two kinds of closures:

Closures that act like anonymous functions:

  1. Argument passing has method semantics
  2. Return will exit the closure

And closures that syntactic elements:

  1. Arguments passing has assignment semantics
  2. Return will exit the creating context

Lambdas and stabby lambdas (i.e ->() { }) are the anonymous function types of closures. These closures are great when you want to create closures that act like functions.

Procs and implicit blocks are the syntactic element type of closure. You use this type of closure where you want to build things like loops or other syntactic elements using closures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment