In this series of posts, we already covered that *methods can be transformed into procs* and as such, can be evaluated **later**. Furthermore, we've seen that procs can be used as arguments to another methods and that such procs can optionally use curried arguments.

Until now, we have been using methods as a way to represent "blocks" of code:

```
def multiply(a, b)
a * b
end
```

Also, we learned that, in order to evaluate a method **later**, we must transform it into a proc (`method(:some_method)`

). In Ruby, we can represent *blocks* of code to be *evaluated later* not only in methods, but also creating procs directly:

```
current_time = Proc.new { Time.now }
current_time.call # => 2021-04-10 17:22:06
# It's quite similar to using methods
def current_time
Time.now
end
method(:current_time).call # => 2021-04-10 17:22:10
```

Then, blocks can represent any **group of code** which will be evaluated later. Blocks can be inline or multiline:

```
# inline block
Proc.new { Time.now }
# multine block
Proc.new do
Time.now
end
```

Let's take our example in the previous post about `map_numbers`

and, instead of creating a method `multiply`

, we define a `Proc`

directly with a block:

```
multiply = Proc.new { |a, b| a * b }
multiply.call(2, 3) # => 6
multiply.curry[2].call(4) # => 8
```

Right. Now, remember that the implementation of `map_numbers`

takes a proc as the last argument? Then we have nothing to do in that method. It will simply work, because the object passed as argument should respond to a method `call`

, so in this case procs already do!

```
multiply = Proc.new { |a, b| a * b }
map_numbers([1, 2, 3], multiply.curry[2]) # => [2, 4, 6]
```

We could also use another way of creating a proc, which is a `lambda`

. There are slight differences between procs and lambdas, but both belong to the same Ruby class: Proc, with lambda being a "type" of Proc.

```
multiply_proc = Proc.new { |a, b| a * b }
multiply_proc.call(2, 3) # => 6
multiply_lambda = -> (a,b) { a * b }
multiply_lambda.call(2, 3) # => 6
# let's bring methods into play
def multiply(a, b)
a * b
end
method(:multiply).call(2, 3) # => 6
```

"Meta" methods, procs, lambdas...they have little differences in practice but they all:

- take blocks
- respond to
`.call`

- respond to
`.curry`

- and share other similarities... Take a look at the Proc and Method documentation.

YAY! That's so much power!

### A syntactic sugar

Our method `map_numbers`

looks like this:

```
def map_numbers(numbers, calculation_proc)
# logic here
# somewhere, it does `calculation_proc.call(number)`
end
```

The standard Ruby gives us a *syntactic sugar*, a keyword called **yield**, which is as similar as calling `some_proc.call`

. If we choose to use `yield`

, we can omit the `proc`

parameter but we have to trust that whoever calls the method, they must *ensure* the proc was passed as the **last** argument.

```
def map_numbers(numbers)
new_list = []
for number in numbers
new_list << yield(number) # <--- similar as doing the proc call
end
new_list
end
```

Now, if we try to call:

```
map_numbers([1, 2, 3], method(:multiply).curry[2])
```

Oh,oh:

```
ArgumentError (wrong number of arguments (given 2, expected 1))
```

That's because, this syntactic sugar has a rule of thumb: the argument cannot be a proc, but a **BLOCK** instead. For doing so, we have to *transform* our proc into a block, upon the passing argument, by prepending a `&`

in the proc object:

```
map_numbers([1, 2, 3], &method(:multiply).curry[2]) # => [2, 4, 6]
```

*The & prepend can be used to transform procs into blocks ONLY upon methods passing arguments!*

### Passing blocks to methods

Similar as using blocks to define procs and lambdas, we can also use blocks to be passed to methods. In case there's a block being passed, Ruby *WILL always* take the block and use it as the **last argument**.

```
map_numbers([1, 2, 3]) { |number| number * 2 } # => [2, 4, 6]
map_numbers([1, 2, 3]) { |number| number * 3 } # ...
map_numbers([1, 2, 3]) { |number| number + 55 } # ...
# multiline
map_numbers([1, 2, 3]) do |number|
number * 10
end
```

Thankfully, we don't need to create such a method `map_numbers`

in our codebase. Ruby has a lot of useful methods in its standard library, and the method `map`

is one of them, being part of the Array class:

```
[1, 2, 3].map { |number| number * 2 } # => [2, 4, 6]
```

And, since we know that methods can be transformed into procs:

```
multiply_by_two = 2.method(:*) # 2 is an object, don't forget!
[1, 2, 3].map(&multiply_by_two)
```

So, unleash the madness and abuse on the syntactic sugar!

```
[1, 2, 3].map(&2.method(:*)) # multiply by 2
[1, 2, 3].map(&6.method(:+)) # sum by 6
```

### Reducing structures

What if we wanted to sum all numbers in a list? Well, that's a simple algorithm:

```
def sum_all(numbers)
sum = 0
for number in numbers
sum += number
end
end
```

But how can we write a more *flexible and robust* code that allows to apply any *transformation*, **reducing** the entire list into a single **accumulated** value, no matter if the desired output is a sum or the product of multiplication?

Yes, we can rely on blocks!

```
def reduce(numbers, initial_acc)
accumulator = initial_acc
for number in numbers
accumulator = yield(accumulator, number)
end
accumulator
end
```

Then, we can use our method to apply a bunch of reducers:

```
# sum all numbers
reduce([1, 2, 3], 0) { |acc, number| acc = acc + number }
# multiply all numbers
reduce([1, 2, 3], 1) { |acc, number| acc = acc * number }
# syntactic sugar
reduce([1, 2, 3], 0, &:+) # sum all numbers
reduce([1, 2, 3], 1, &:*) # multiply all numbers
```

Similar to `map`

, Ruby also provides a method `reduce`

in the standard library:

```
[1, 2, 3].reduce(0) { |acc, number| acc += number }
[1, 2, 3].reduce(1) { |acc, number| acc *= number }
[1, 2, 3].reduce(&:+)
[1, 2, 3].reduce(&:*)
```

## Wrapping up

In this series of blogposts, we tried to cover the fundamentals behind Ruby blocks, such as:

- how Ruby evaluates expressions
- how we can use methods to evaluate expressions later
- methods and procs
- procs as arguments
- curry arguments in procs
- blocks in procs, lambdas and methods
- bonus point to syntactic sugar and the Ruby standard library

I hope you could enjoy and understand a bit more on how Ruby blocks work and how to make a more effective use of them on a daily basis!

## Top comments (0)