Blocks Procs and Lambdas

Ruby has three types of anonymous functions: Blocks, Procs and Lambdas.

====== Block ======

Blocks are anonymous pieces of code that are not objects but can be passed to methods for execution. An example is the map method from the Enumerable mixin, which accepts and executes a block of code:

[1,2,3].map { |x| x* 2 }

Methods explicitly or implicitly accept blocks:

def method_implicit
  puts "Starting the method"
  yield if block_given?
  puts "ending"
end

def method_explicit(&block)
  puts "Starting explicit"
  block.call
  puts "ending explicit"
end

In the first case, the method uses yield to execute the block if provided. In the second case, the &block syntax indicates that the method expects a block as an argument. One more thing to remember is that when the block is executed the control passes to it and returns to the method when the block has finished its execution.

====== Proc ======

Unlike blocks, Proc - from the Ruby docs - are objects which encapsulate blocks of code. They can be stored in a variable, passed to a method or to other Procs. Proc are closures,meaning they remember and can use the entire context in which they were created. For instance:

pow_two = Proc.new { |x| x**2 }
pow_two.call(3) # Output: 9

Procs retain access to variables in their creation context:

def create_proc
  local_variable = "I am from the original scope"
  proc = Proc.new do
    puts local_variable
  end
  proc
end

# Create a Proc in one scope
my_proc = create_proc

# Call the Proc in a different scope
my_proc.call # Output: I'm from the original scope

It’s worth mentioning that this could potentially lead to troubles if the creation context is not available anymore or has changed such in the case of serialization/deserialization or if used in a different object or class context.

Consider now this example:

def another_proc
  local_var = "I'm local"
  proc = Proc.new { return local_var }
  proc.call
  return "another one"
end

irb(main):053:0> puts another_proc
I'm local

Procs do not pass back control to the calling method but immediately return.
They are generous about accepting arguments. Missing ones will be fit with nil, single Array will be deconstructed if having multiple arguments and no errors will be raised on extra ones.

====== Lambda ======

Lambdas are objects of the Proc class created using the kernel#lambda semantics. They are stricter with passed arguments compared to regular Procs. Notably, return and break in a lambda exits the lambda and returns control to the calling function:

def lambda_method
  local = "I'm local"
  lam = lambda {return local }
  puts lam.call
  puts "end"
end

lambda_method # Output: I'm local end

Understanding when to employ each of these constructs is crucial for writing clean and efficient Ruby code. Blocks are excellent for short, one-off operations, Procs offer encapsulation and context retention, while Lambdas provide a balance of strict argument handling and the familiarity of Proc behavior.


Things I like - in random order

The Astronomy Picture of the Day is something beautiful: Cathedral, Mountain, Moon

Probably a lot of people started using a computer with Windows installed - a stock Windows 3.1 on the Internet Archive

What an extraordinary historical archive: BBC Computer Literacy Project 1980 - 1989


The Acorn BBC Micro

the acorn bbc micro computer


They say that electronic mail tends to be informal in style (as opposed to written mail) and makes people bolder. This encourages those who wouldn’t dare to say something direct to your face (and who don’t have anything serious enough to say to commit it to a formal, written memo) to send you “brazen” messages.

Sounds familiar? An old article about email and conventional post - 1983 Could electronic mail undermine conventional post?

Ruby 3.3 has been released with some really interesting additions to the language

The Most Important Unsolved Problem in Computer Science Scientific American

Good news you didn’t hear about Futurecrunch