Page Content

Tutorials

What Is Code Blocks In Ruby With Practical Code Examples

Code Blocks in Ruby

Code blocks connected to a method call are called Ruby code blocks. Instances of the Proc class must be created whenever a program wants to handle these anonymous code segments as objects that can be passed around, stored, or returned.

Ruby provides two ways to describe code blocks as runnable, parameterized objects: Proc objects and Lambda objects. Custom control structures and functional programming approaches are made possible by these basic ideas.

Proc Objects (The Object Form of a Block)

Blocks are not objects; they are syntactic structures. A block can be converted into an instance of the Proc class, which is called a Proc object.

Creation and Conversion

The creation of procs can be done explicitly with Proc.new or implicitly by passing it into a method parameter that has an ampersand (&) before it:

Using Proc.new: This is how a Proc class instance is typically created.

Using Kernel#proc: This is a Ruby 1.9+ synonym for Proc.new. (Note: Lambda is the preferred term for method-like behavior in Ruby 1.8 instead of proc, which created ambiguity.)

Code Example: Creating a Proc

# 1. Using Proc.new to create a Proc object explicitly
p = Proc.new { |x, y| x + y } 
puts p.class # => Proc

# 2. Passing a block to a method and capturing it with &
def get_proc(&block)
  # The &block syntax converts the passed block into a Proc object
  block 
end

addition_proc = get_proc { |a, b| a + b }
puts addition_proc.call(5, 10) # => 15

Output

Proc
15

You can also read File I/O In Ruby: Basic Operations To Advanced File Handling

Lambda Objects

Although lambdas are likewise instances of the Proc class, their behavior is slightly different and more akin to that of a method than a block.

If you want your code to act as a formal method or function, lambdas are better than standard Procs.

Creation

Using Kernel#lambda: This is the traditional way of making a lambda.

Using Arrow Syntax (->): In Ruby 1.9, an arrow (->) was added to the literal syntax for lambdas, which is thought to be more elegant.

Code Example: Creating a Lambda

# 1. Using the lambda method
is_positive = lambda { |x| x > 0 } 
puts is_positive.class # => Proc (Lambdas are a special type of Proc)
puts is_positive.call(5) # => true

# 2. Using the arrow syntax (->)
greeting = ->(name) { "Hello #{name}!" } 
puts greeting.call("Sven") # => Hello Sven!

# Lambdas created via arrow syntax can include default arguments (Ruby 1.9+)
zoom = ->(x, y, factor=2) { [x * factor, y * factor] }
puts zoom.call(10, 5).inspect # => [20, 10]

Output

Proc
true
Hello Sven!
[20, 10]

You can also read What Is Command Line Crash Course Navigation In Ruby

Invocation

Since the Proc class defines all of the methods needed to run the embedded code, many methods can be used to invoke both Procs and Lambdas:

  • #call (The standard method).
  • [] (The array access operator).
  • .() (Ruby 1.9+ syntactic sugar).

Blocks as Closures

Lambdas are closures, as are Procs. Even if the variable bindings (local variables that were in scope when the object was defined) later leave scope, a closure still has access to them.

# Example illustrating closure (the lambda closes over the variable 'n')
def multiplier(n)
  # 'n' is retained by the lambda, even after multiplier returns
  lambda { |data| data.collect { |x| x * n } } 
end

doubler = multiplier(2) # Sets n=2 in the closure
puts doubler.call([65-67]) # Prints 2,4,6 

tripler = multiplier(3) # Sets n=3 in a separate closure
puts tripler.call([65-67]) # Prints 3,6,9

Output

-4
-6

You can also read What Is The Command Line Crash Course Manipulation in Ruby

Key Differences (Proc vs. Lambda)

Argument strictness (arity) and the return keyword’s effect are the two major traits that distinguish Procs (or “raw procs” defined via Proc.new) from Lambdas.

Argument Arity

Lambdas are strict (method-like): It is necessary to call them with the exact number of arguments that they were intended to accept. If this isn’t done, an ArgumentError is raised.

Procs are flexible (block-like): They act similarly to blocks when called via yield, ignoring extra arguments and assigning nil to missing arguments.

# The complete code demonstrating argument handling differences

# 1. Lambda (STRICT Argument Count)
l = lambda {|x, y| x + y}
puts "--- Lambda (l) Examples ---"
puts "l.call(1, 2)  => #{l.call(1, 2)}"
# l.call(1)       # UNCOMMENT TO SEE: ArgumentError: wrong number of arguments (given 1, expected 2)
# l.call(1, 2, 3) # UNCOMMENT TO SEE: ArgumentError: wrong number of arguments (given 3, expected 2)


# 2. Proc (LAX Argument Count)
p = Proc.new {|x, y| x + y}
puts "\n--- Proc (p) Examples ---"

# Correct number of arguments
puts "p.call(1, 2)  => #{p.call(1, 2)}"

# Too few arguments (y is nil, leads to TypeError: nil can't be coerced into Integer)
puts "p.call(1)     => ERROR BELOW"
puts "---"
# This line is the one that produces the error you saw:
# p.call(1) # UNCOMMENT TO SEE: TypeError: nil can't be coerced into Integer (from 1 + nil)

# Too many arguments (extra arguments are ignored)
puts "p.call(1, 2, 3) => #{p.call(1, 2, 3)}"

Output

--- Lambda (l) Examples ---
l.call(1, 2)  => 3

--- Proc (p) Examples ---
p.call(1, 2)  => 3
p.call(1)     => ERROR BELOW
---
p.call(1, 2, 3) => 3

You can also read Method Visibility In Ruby : Public, Private, And Protected

Return Behavior

The main functional distinction between a Lambda and a Proc is the impact of the return statement in the former.

  • return in a Proc causes a non-local return, meaning it attempts to exit the entire method that enclosed the Proc’s definition, not just the Proc itself. If the enclosing method has already completed, this raises a LocalJumpError.
  • return in a Lambda causes a local return, meaning it returns control only from the lambda, just like a regular method call.
def test_proc
  p = Proc.new { puts "In Proc"; return "Proc Result" }
  puts "Before Proc Call"
  p.call # Immediately exits test_proc method
  puts "After Proc Call" # This line is never reached 
end

def test_lambda
  l = lambda { puts "In Lambda"; return "Lambda Result" }
  puts "Before Lambda Call"
  result = l.call # Returns only from the lambda, execution continues
  puts "After Lambda Call: #{result}" 
end

test_proc 
# Output: 
# Before Proc Call
# (Method exits, returning "Proc Result" to its caller)

test_lambda

Output

Before Proc Call
In Proc
Before Lambda Call
In Lambda

You can also read What Is Inheritance In Ruby With Practical Code Examples

Agarapu Geetha
Agarapu Geetha
My name is Agarapu Geetha, a B.Com graduate with a strong passion for technology and innovation. I work as a content writer at Govindhtech, where I dedicate myself to exploring and publishing the latest updates in the world of tech.
Index