Ruby is a language that consistently evolves to make code more expressive, concise, and readable. With the release of Ruby 3.4, one of the exciting new features introduced is the use of it
as a shortcut for the first parameter in a block. This enhancement aims to simplify code, especially in situations where blocks are used extensively, reducing the need to explicitly declare block parameters.
In this post, we’ll explore how the it
shorthand works, why it was introduced, and when it’s useful.
What Is the it
Shorthand?
The it
keyword is now an implicit reference to the first block parameter. This means that instead of having to define a block parameter explicitly, you can use it
as a reference within the block, improving both readability and brevity.
Here’s a comparison between the traditional approach and the new it
shorthand:
Before:
1
[1, 2, 3].map { |num| num * 2 }
Using it
:
1
[1, 2, 3].map { it * 2 }
In this example, it
implicitly refers to the first parameter passed to the block, which in this case is each element of the array. This removes the need to explicitly name the block parameter (num
), making the code shorter and easier to read, especially in simple cases like this.
Why Introduce the it
Shorthand?
Ruby has always emphasized developer happiness, and one of its core principles is that code should be as intuitive and concise as possible. The introduction of it
follows this philosophy by:
-
Reducing Boilerplate: In many cases, block parameters are used without any transformations or complex logic. Instead of repeatedly declaring a single block variable,
it
provides a clean and simple alternative. -
Improving Readability: For developers familiar with other languages like Scala or Kotlin, where similar features exist (
_
orit
being used for block parameters), this change brings Ruby more in line with modern syntactic trends, making code easier to follow at a glance. -
Encouraging Simplicity: For straightforward blocks that only work with a single parameter, using
it
can encourage more concise expressions, promoting the Ruby style of clean, minimal code.
Examples of Using it
Let’s look at a few examples where it
can improve readability and reduce the need for explicit parameter declarations.
Example 1: Using map
with it
1
2
3
4
5
# Before
[1, 2, 3].map { |n| n + 1 }
# Using `it`
[1, 2, 3].map { it + 1 }
In this case, it
refers to each element of the array, making the operation simpler to read and write.
Example 2: Selecting Elements from an Array
1
2
3
4
5
6
# Before
words = %w[apple orange banana]
filtered_words = words.select { |word| word.length > 5 }
# Using `it`
filtered_words = words.select { it.length > 5 }
Here, the block becomes more concise by eliminating the need to declare the block variable word
.
Example 3: Sorting with it
1
2
3
4
5
6
# Before
numbers = [3, 1, 4, 2]
sorted_numbers = numbers.sort_by { |num| num }
# Using `it`
sorted_numbers = numbers.sort_by { it }
For simple sorting operations where only the first parameter is used, the it
shorthand significantly reduces the visual clutter.
When Should You Use it
?
While it
is a great tool for improving readability, it’s important to recognize when it is appropriate to use and when it’s better to stick with explicit block parameters.
Good Use Cases:
- Single-Parameter Blocks: The primary use case for
it
is when a block operates on a single parameter without needing multiple or nested parameters. - Simple Operations: If the block performs a single, clear operation,
it
helps keep the code concise and clean.
When to Avoid it
:
- Complex Blocks: If your block has multiple parameters or involves complex logic, it’s better to use explicitly named parameters. Using
it
in such cases can obscure the intent and make the code harder to understand. - Nested Blocks: When dealing with nested blocks or lambdas, using
it
can be confusing. It’s better to explicitly name your block parameters to avoid ambiguity in those cases.
For example:
1
2
3
4
# Avoid using `it` in complex or nested blocks
some_data.each do |item|
item.nested_data.map { |nested_item| nested_item.do_something(it) } # This would be unclear
end
In this scenario, using it
in a nested context can lead to confusion about which parameter is being referred to. Explicitly naming parameters is preferable here.