Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is Lambda in Ruby?

In this blog post, we will explore Lambda in Ruby, a powerful and flexible feature that allows you to create anonymous functions, which can be used as first-class objects or passed around as arguments. This post will be catered to those who are learning programming and may not be familiar with all the jargons and terminology used in the software development world. With that said, let's dive in!

What is a Lambda?

To put it simply, a lambda is a way to define a small, anonymous function in your code. Anonymous functions, as the name suggests, are functions that don't have a specific name. These functions can be used as first-class objects, meaning you can pass them as arguments to other functions, store them in data structures, and even return them as values from other functions.

In Ruby, lambdas are created using the lambda keyword or the -> (stabby lambda) syntax. The two syntaxes are equivalent and interchangeable. Let's take a look at an example:

# Using the lambda keyword
add = lambda { |a, b| a + b }

# Using the stabby lambda syntax
add = ->(a, b) { a + b }

Both of these lambdas define a simple function that takes two arguments, a and b, and returns their sum. To call a lambda, you can use the call method:

result = add.call(2, 3)
puts result # Output: 5

Now, you might wonder why we would use lambdas instead of regular methods. The reason is that lambdas provide greater flexibility in certain situations, such as when you want to pass a custom piece of code to a method or when you want to store a function in a data structure. We'll explore these use cases in more detail later in this post.

Lambda vs. Proc

Before we dive deeper into the world of lambdas, it's important to make a distinction between lambdas and procs. In Ruby, both lambdas and procs are used to create anonymous functions, and they share many similarities. However, there are some key differences that set them apart:

Argument checking: Lambdas are strict when it comes to the number of arguments passed to them. If you pass the wrong number of arguments to a lambda, it will raise an ArgumentError. On the other hand, procs are more lenient; if you pass too few arguments, they will use nil for the missing ones, and if you pass too many, they'll simply ignore the extra ones.

Return behavior: When you use a return statement inside a lambda, it only returns from the lambda itself. However, when you use return inside a proc, it tries to return from the enclosing method, which can lead to unexpected results.

Here's an example illustrating these differences:

def test_lambda_and_proc
  my_lambda = ->(a, b) { return a + b }
  my_proc = Proc.new { |a, b| return a + b }

  puts "Lambda: #{my_lambda.call(1, 2)}" # Output: Lambda: 3
  puts "Proc: #{my_proc.call(1, 2)}" # No output, as it tries to return from test_lambda_and_proc
end

test_lambda_and_proc

In this example, calling the lambda works as expected, whereas calling the proc leads to an unexpected result, as it tries to return from the enclosing method. This difference in behavior can be important when you're working with anonymous functions in your Ruby code.

Now that we've covered the basics and differences between lambdas and procs, let's dive into some practical examples and use cases for lambdas.

Use Case 1: Higher-Order Functions

One of the most common use cases for lambdas is as arguments to higher-order functions. A higher-order function is a function that takes one or more functions as arguments, and/or returns a function as its result. These functions can be used to create more modular and reusable code by allowing you to pass custom behavior to a function.

Let's take a look at an example: implementing a custom map function that takes an array and a lambda as arguments and returns a new array containing the result of applying the lambda to each element of the input array.

def custom_map(array, lambda)
  result = []
  array.each { |element| result << lambda.call(element) }
  result
end

# Example usage:
doubled_numbers = custom_map([1, 2, 3, 4, 5], ->(x) { x * 2 })
puts doubled_numbers.inspect # Output: [2, 4, 6, 8, 10]

In this example, we define a custom_map function that takes an array and a lambda. We then iterate over the input array, apply the lambda to each element, and store the result in a new array. Finally, we return the new array.

When we call custom_map with an array of numbers and a lambda that doubles each number, we get a new array with the doubled numbers.

Use Case 2: Storing Functions in Data Structures

Another use case for lambdas is storing functions in data structures, such as arrays or hashes. This can be useful when you want to create a collection of functions that can be accessed and executed based on some condition or key.

Here's an example of storing lambdas in a hash and using them to perform arithmetic operations:

operations = {
  add: ->(a, b) { a + b },
  subtract: ->(a, b) { a - b },
  multiply: ->(a, b) { a * b },
  divide: ->(a, b) { a / b }
}

puts "2 + 3 = #{operations[:add].call(2, 3)}" # Output: 2 + 3 = 5
puts "10 - 5 = #{operations[:subtract].call(10, 5)}" # Output: 10 - 5 = 5
puts "3 * 4 = #{operations[:multiply].call(3, 4)}" # Output: 3 * 4 = 12
puts "9 / 3 = #{operations[:divide].call(9, 3)}" # Output: 9 / 3 = 3

In this example, we define a hash called operations that stores various arithmetic operations as lambdas. We can then access and call these lambdas using their corresponding keys in the hash.

Conclusion

In this post, we've explored what lambdas are in Ruby, how they differ from procs, and some practical use cases for lambdas, such as higher-order functions and storing functions in data structures. Lambdas are a powerful and flexible feature of Ruby that can help you write more modular and reusable code.

As you continue learning programming and working with Ruby, remember that while lambdas can be incredibly useful in certain situations, it's important to use them judiciously and not overcomplicate your code.

Happy coding!