Ruby Lambda

Anonymous functions with strict argument checking

λ What are Ruby Lambdas?

Lambdas are anonymous functions that can be stored in variables and passed around. They check argument counts strictly and return to the calling method, making them predictable and safe.


# Create a lambda
greet = lambda { |name| puts "Hello, #{name}!" }

# Call the lambda
greet.call("Alice")

# Shorter syntax
square = ->(x) { x * x }
puts square.call(5)
                                    

Output:

Hello, Alice!

25

Key Lambda Features

📦

Object

Lambdas are objects you can store

add = lambda { |a, b| a + b }
result = add.call(2, 3)

Strict Args

Checks argument count

fn = ->(x) { x * 2 }
fn.call(5)  # Works
# fn.call() raises error
↩️

Return

Returns to calling method

fn = -> { return 42 }
fn.call  # Returns 42

Syntax

Two ways to create lambdas

lambda { |x| x }
->(x) { x }

🔹 Creating Lambdas

Ruby provides two syntaxes for creating lambdas: the traditional lambda keyword and the stabby lambda (->). Both create identical objects, but the stabby syntax is more concise and commonly preferred in modern Ruby code.

# Traditional lambda syntax
greet = lambda { |name| "Hello, #{name}!" }
puts greet.call("Bob")

# Stabby lambda syntax (->)
multiply = ->(a, b) { a * b }
puts multiply.call(4, 5)

# Lambda without parameters
say_hi = -> { "Hi there!" }
puts say_hi.call

# Multi-line lambda
calculate = lambda do |x, y|
  sum = x + y
  product = x * y
  "Sum: #{sum}, Product: #{product}"
end

puts calculate.call(3, 4)

Output:

Hello, Bob!

20

Hi there!

Sum: 7, Product: 12

🔹 Calling Lambdas

Lambdas can be invoked using multiple methods: .call(), square brackets [], or parentheses (). All three work identically, but .call() is most explicit and commonly used for clarity in production code.

# Create a lambda
double = ->(x) { x * 2 }

# Method 1: .call()
puts double.call(5)

# Method 2: Square brackets
puts double[6]

# Method 3: Parentheses (Ruby 1.9+)
puts double.(7)

# With multiple arguments
add = ->(a, b, c) { a + b + c }
puts add.call(1, 2, 3)
puts add[10, 20, 30]

Output:

10

12

14

6

60

🔹 Strict Argument Checking

Unlike Procs, lambdas enforce strict argument checking. If you pass the wrong number of arguments, Ruby raises an ArgumentError. This strictness helps catch bugs early and makes code more predictable and maintainable.

# Lambda requires exact arguments
greet = ->(name, age) { "#{name} is #{age}" }

# Correct number of arguments
puts greet.call("Alice", 25)

# Wrong number causes error (commented to prevent crash)
# greet.call("Bob")  # ArgumentError: wrong number of arguments

# Default parameters work
welcome = ->(name, greeting = "Hello") { "#{greeting}, #{name}!" }
puts welcome.call("Charlie")
puts welcome.call("Diana", "Hi")

# Optional parameters with splat
sum = ->(*numbers) { numbers.sum }
puts sum.call(1, 2, 3)
puts sum.call(10, 20)

Output:

Alice is 25

Hello, Charlie!

Hi, Diana!

6

30

🔹 Lambdas as Arguments

Lambdas can be passed to methods as arguments, enabling powerful functional programming patterns. This allows you to inject custom behavior into methods, creating flexible and reusable code structures for callbacks and transformations.

# Pass lambda to method
def apply_operation(a, b, operation)
  operation.call(a, b)
end

add = ->(x, y) { x + y }
multiply = ->(x, y) { x * y }

puts apply_operation(5, 3, add)
puts apply_operation(5, 3, multiply)

# Array methods with lambdas
numbers = [1, 2, 3, 4, 5]

is_even = ->(n) { n.even? }
evens = numbers.select(&is_even)
puts "Evens: #{evens.inspect}"

double = ->(n) { n * 2 }
doubled = numbers.map(&double)
puts "Doubled: #{doubled.inspect}"

Output:

8

15

Evens: [2, 4]

Doubled: [2, 4, 6, 8, 10]

🔹 Returning Lambdas

Methods can return lambdas, creating closures that remember their surrounding context. This powerful feature enables factory patterns, currying, and creating specialized functions dynamically based on runtime conditions.

# Method returns a lambda
def multiplier(factor)
  ->(n) { n * factor }
end

times_two = multiplier(2)
times_three = multiplier(3)

puts times_two.call(5)
puts times_three.call(5)

# Lambda factory
def greeter(greeting)
  ->(name) { "#{greeting}, #{name}!" }
end

say_hello = greeter("Hello")
say_hi = greeter("Hi")

puts say_hello.call("Alice")
puts say_hi.call("Bob")

# Closure example
def counter
  count = 0
  -> { count += 1 }
end

increment = counter
puts increment.call
puts increment.call
puts increment.call

Output:

10

15

Hello, Alice!

Hi, Bob!

1

2

3

🔹 Practical Lambda Examples

Lambdas excel in real-world scenarios like data validation, transformation pipelines, and callback systems. These examples show how lambdas create clean, testable code for common programming patterns in Ruby applications.

# Validation lambdas
is_valid_email = ->(email) { email.include?("@") && email.include?(".") }
is_valid_age = ->(age) { age >= 18 && age <= 100 }

puts is_valid_email.call("[email protected]")
puts is_valid_age.call(25)

# Data transformation pipeline
trim = ->(str) { str.strip }
upcase = ->(str) { str.upcase }
add_prefix = ->(str) { "USER: #{str}" }

process = ->(input) {
  result = trim.call(input)
  result = upcase.call(result)
  add_prefix.call(result)
}

puts process.call("  alice  ")

# Calculator with lambdas
operations = {
  add: ->(a, b) { a + b },
  subtract: ->(a, b) { a - b },
  multiply: ->(a, b) { a * b },
  divide: ->(a, b) { b != 0 ? a / b : "Error" }
}

puts operations[:add].call(10, 5)
puts operations[:multiply].call(4, 3)

Output:

true

true

USER: ALICE

15

12

🧠 Test Your Knowledge

What happens if you pass the wrong number of arguments to a lambda?