Introduction to Blocks, Procs & Lambdas in Ruby
Tags: ruby, programming
Published: 2023-02-17 11:24:27

### Block

Blocks are a set of instructions that can be passed to a method for execution. They are enclosed in a `do-end` block or between curly braces `{}`. Blocks can take multiple arguments, and their argument names are defined between two pipe characters `||`.

Here's an example of a block that we can pass to the each method:

```ruby
[1, 2, 3].each { |num| puts num }
```
In the above code, `|num|` is the argument of the block, and `puts num` is the instruction that will be executed on each element of the array.

### Yield

Yield is a Ruby keyword that executes a block of code passed to a method. The code inside the block will run when you use the `yield` keyword.
Here's an example of a method that takes a block and uses the yield keyword to execute it:

```ruby
def print_hello
  yield
end

print_hello { puts "Hello" }
```

In this example, the `yield` statement will execute the code inside the block and print "Hello" to the console.

You can also pass arguments to yield:

```ruby
def one_two_three
  yield 1
  yield 2
  yield 3
end

one_two_three { |number| puts number * 2 }
# 2, 4, 6
```
Here, we are passing the numbers 1, 2, and 3 to the block and printing their multiples of 2 to the console.

### Implicit vs Explicit Blocks

There are two ways to define a block in Ruby: implicit and explicit. An implicit block is not given a name in the parameter list. It is called using the yield keyword. On the other hand, an explicit block is given a name in the parameter list.
Here's an example of an explicit block:

```ruby
def explicit_block(&block)
  block.call # same as yield
end

explicit_block { puts "Explicit block called" }
```

In the above example, the `&block` parameter is used to define the block's name. This allows us to pass the block to another method or save it into a variable to use later.

If you try to `yield` without a block, you will get a no `block given (yield)` error. To check if a block has been passed in, you can use the `block_given?` method.

### Lambda

A lambda is a way to define a block and its parameters using a special syntax. A lambda can take arguments, and it won't run the code inside it until you call it using the `call` method.

Here's an example of a lambda:

```ruby
hello_world = -> { puts "Hello world" }
hello_world.call

# "Hello World"
```

Lambdas can also take arguments, just like methods:

```
times_two = ->(x) { x * 2 }
times_two.call(10)
# 20
```

If you pass the wrong number of arguments to a `lambda`, it will raise an exception, just like a regular method.

### Lambdas vs Procs

Procs are a very similar concept to lambdas, but with a few key differences. One of the differences is how you create them:

```ruby
my_proc = Proc.new { |x| puts x }
```

A proc behaves differently than a lambda, especially when it comes to arguments. A proc will not raise an exception if you pass the wrong number of arguments to it:

```ruby
my_proc.call(1, 2, 3) # prints 1

```
In this example, the proc only takes one argument, but we passed in three. The extra arguments are ignored.

Another difference between procs and lambdas is how they react to a `return` statement. A lambda will `return` normally, like a regular method. But a proc will try to `return` from the current context:

```ruby
def test_proc
  my_proc = Proc.new { return "returning from proc" }
  my_proc.call
  return "returning from method"
end

def test_lambda
  my_lambda = -> { return "returning from lambda" }
  my_lambda.call
  return "returning from method"
end

puts test_proc # prints "returning from proc"
puts test_lambda # prints "returning from method"
```
In this example, the `test_proc` method returns from the proc instead of continuing to execute the method. The `test_lambda `method, on the other hand, returns normally because the lambda behaves like a regular method.