New Features, Methods & Improvements in Ruby 2.7

Ruby never stops improving!

Version 2.7 is around the corner with new features & methods. It’s scheduled for release on December 25, 2019.

Now, according to Matz…

This is the last 2.x version release. Because next year we’re getting Ruby 3.0!

But before we get there…

Let’s take a look at some of the changes & new features in 2.7, so you can be ready for the version update.

Enumerable#tally

This is a new Ruby method that counts all the elements in an array & returns a hash with their counts.

You can do this yourself, but this tally method saves you work.

Here’s an example:

%w(a a a b b c).tally

Which results in:

{"a"=>3, "b"=>2, "c"=>1}

I like it!

Numbered Parameters For Blocks [Experimental]

An interesting new feature, which I’ve been wanting for a while, is a default name for block parameters.

Here’s a regular block, with one parameter:

[1,2,3].each { |n| puts n }

This |n| is the parameter, which you have to define to use it.

But what if we had a default name?

Well, that’s one of the goodies that Ruby 2.7 brings with it, although as an experimental feature, it can save us a lot of typing.

Here’s what it looks like:

[1,2,3].each { puts _1 }

Where _1 refers to the first parameter, you can use _2 if you have a 2nd one, and yes, _3 for a 3rd parameter, etc.

Pretty cool!

Now, a little bit of trivia.

This feature was first proposed to look like @1, but that looks too much like an instance variable, so after some discussion, it was settled on using _1 instead.

Array#intersection

New method, but no new functionality.

Actually…

This is more like an alias!

Ruby 2.6 introduced Array union & difference methods, to match the more succinct equivalents of Array#|, and Array#-.

But the missing operation was intersection, which has another hard to remember short version.

The Array#& method.

Now:

What do these methods do & how do they work?

Example:

[1, 2, 3].intersection([2, 3, 4])
# [2, 3]

[1, 2, 3] & [2, 3, 4]
# [2, 3]

Well…

The name kind of gives it away, intersection finds the intersection between two arrays. In other words, it finds which elements are in common.

Short Version Long Version
& intersection
| union
difference

I always forget which one of these 3 methods does what!

But with these new methods, it’s a lot easier to remember because their names mean something.

That’s a good lesson in writing good code, btw.

Enumerable#filter_map

This filter_map method is an attempt to combine the select & map methods into one.

Why?

Because it’s a common operation to filter a list first, then map the remaining elements.

You can do this in two ways:

(1..8).select(&:even?).map { |n| n ** 2 }

# OR

(1..8).map { |n| n ** 2 if n.even? }.compact

I’ve used both, but I tend to lean into the first because the intention is more clear.

Now:

In Ruby 2.7, this filter_map method does this in one pass.

Like this:

(1..8).filter_map { |n| n ** 2 if n.even? }
# [4, 16, 36, 64]

I’m not the biggest fan of having if statements inside blocks, but sometimes they’re needed to get the job done.

Besides that, there is something you should know.

The filter_map operation doesn’t behave like map + compact, because it removes false objects, and compact doesn’t.

A good thing to keep in mind!

Enumerator#produce

Here’s another new method you may find interesting, but it may require some creativity to get the most out of it.

It’s the Enumerator#produce method.

What does it do?

According to the feature proposal:

“This method produces an infinite sequence where each next element is calculated by applying the block to the previous element.”

Yep.

Another way to create never-ending sequences!

Here’s an example:

Enumerator.produce(1, &:next).take(5)
# [1, 2, 3, 4, 5]

In this example, it doesn’t matter if you do take(10) or take(10_000), you’ll get an infinite number of values from it.

Btw, 1 is the initial value.

And &:next is the method called on that value to produce the next element in the sequence.

IRB Gets a Face Lift?

Lately, IRB has been getting some love & attention, and Ruby 2.7 keeps adding to that.

We’re getting:

  • Multi-line editing
  • Syntax Highlighting
  • Built-in RDoc integration
  • Command history enabled by default
  • Auto-completion enabled by default

In fact:

This is such a BIG change that you get a warning when you start up irb with Ruby 2.7.

If you wish to keep using the old version of irb you still can, with the irb --legacy command. My main issue with this new IRB is line editing, in legacy IRB (or in Pry) I can hold ALT & press left arrow to move faster, but this doesn’t work in the new IRB.

Give it a try & see how it works for you.

Ruby Pattern Matching [Experimental]

An often-requested feature that’s coming in 2.7 is pattern matching.

It’s marked as experimental.

But what is pattern matching & how does it benefit you?

Well, if I understand this correctly, pattern matching is like regular expressions, but for data structures (Array/Hash).

Here’s an example:

[1,2,3] in [a,b,c] # true
[1,2,3] in [a]     # false

If there is a match, these variable names (like a) become local variables you can access.

Example with a hash:

{ a: 1, b: 2, c: [] } in { a: a, b: b, c: [] }
# true

p a
# 1

This uses the in keyword.

It’s not new, but uncommon because before Ruby 2.7 in was only used as part of a for loop (highly discouraged in Ruby), so we get to reuse this keyword for something useful.

Even better

It doesn’t matter what variables you use, a,b,c here works, but f,g,h also works.

It’s all about the pattern!

Other Changes

A few extra changes worth mentioning.

  • New compaction GC improves memory fragmentation
  • Method argument **nil now declares that a method takes no keywords
  • Method argument ... adds an argument forwarding mechanism (parenthesis required, like make_salad(...))
  • Fiber improvements. A new pool of fiber objects (from which new fibers are allocated) makes fibers more efficient
  • Thread improvements. A better, more optimized way of creating threads makes multi-threading faster

What do you think about these?

The NEWS file for 2.7 mentions a 10x performance improvement for both fiber & thread creation, I haven’t tested this myself, but if you do let me know about your results.

Summary

You’re now up to date with the latest changes to the Ruby programming language! You learned about IRB changes, new methods & a few experimental features like pattern matching.

Please share this article to spread the news!

Thanks for reading 🙂

Leave a Comment:

6 comments
Kanad Kumar says last month

Thanks for the post. Good thing about your all posts are very short and descriptive. Again thanks.

Reply
    Jesus Castello says last month

    Thanks for reading 🙂

    Reply
Maciej says last month

Hello,

_1 doesn’t work on preview1 ruby 2.7

Valid parameter is @1

Example int the link
https://www.evernote.com/l/AnPnWvh9LrFNVIG5VepJ0wKaknveZ2QCY9U

Reply
    Jesus Castello says last month

    All examples here are using preview3 🙂

    Reply
Gagan kumar says last month

As always you have posted a great article, I am a great admirer of your work.

Reply
    Jesus Castello says last month

    Thank you! 🙂

    Reply
Add Your Reply