Leonardo Traum in der dritten Nacht

So ging ich dann am zweiten Tage wohlgenährt und viel zu spät ins Bett und ja die Meditation wollte nicht gelingen das wlan war zu schwach und immer wieder stockte es ich würde nur öffne hinter…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Ruby 2.7 experimental pattern matching in few examples

Which one matches that pattern?

This is not technical paper. To make it easier to understand (and for my lack of knowledge) I’m probably not using proper terms and names in this article.

I see pattern matching as 2 steps process:

If you’re advanced Ruby programmer, you should be familiar with deconstructing already.

In Ruby it is already possible to deconstruct array by “multi-assignment” for years. We can take a look at few examples just to remind this. Feel free to skip to next section if you’re familiar with this already.

Looks familiar, doesn’t? We have array of three names and we can deconstruct that array into three variables in one line. If there’s more elements in array than available variables to deconstruct, the rest of the array will be ignored.

When there’s less elements than available variables nil values are used to fill in those "overlapping" variables.

Easy. It is also possible to gather “overlapping” elements using *.

And finally it is possible to skip some elements.

In summary, we do assign array to “multiple variables” and it is deconstructed by rules defined on the left side of assignment. And that’s it. We can consider this “simple pattern matching”. We have pattern on the left side of assignment, data on the right side and data are deconstructed based on pattern (left side).

In Ruby 2.7 there’s experimental support (you’ll see warning on $STDOUT using this feature) for native pattern matching syntax. Let’s try to use new Ruby syntax ( in) to “refactor” our first example with names.

Cool! It works. But how is this more useful than good ol’ plain array deconstruction? Let’s try it with some “non-matching” pattern. We can try to deconstruct array to less variables than elements.

Whoops. We have provided pattern of array having 3 elements and tried to match it to array having 4 elements. Pattern wasn’t matched in this case and exception was raised. If we would like to gather elements in array, we can still use * to define different pattern. Getting back to primes examples with the middle gathering all except first and last element, we can use pattern matching for this as well.

Also it is possible to skip the part we do not care about using the same approach as we did in array deconstructing before (using *).

As you can see the main difference, pattern matching on array is more strict of pattern provided.

Deconstructing of arrays is really useful, but what about another objects? Let’s try to deconstruct hash the old way (similar to array one).

OK, it doesn’t work. Whole hash is just assigned to name and the rest of variables is assigned to nil. I would be really surprised to see this successfully deconstructed, since hash is not ordered structure and we do not provide any rule (pattern) how to deconstruct the hash. Let's try to deconstruct our hash via new Ruby 2.7 way using in.

Providing pattern (recipe how to deconstruct our hash — {name: name, role: position}) was enough to get variables assigned. We can use any variable name for destructing. In original hash there's key role, but we define in pattern to deconstruct that value to variable position.

“Inline deconstructing” is fine, but pattern matching is even more powerful combined with case statement.

We have array of hashes with inconsistent keys and case statement using various patterns.

Only first matched pattern is used. This is same to case when statement.

TIP: If hash key and assigned variable share the same name, we can use shorter definition of pattern in {name:} which is equal to in {name: name}. Shorthand property names (from ES2015) anyone?

I remember reading some Elixir tutorial explaining pattern matching on JSON-like structures. It amazed me and made me envy. There’s nothing similar in Ruby itself. With Ruby 2.7 my dream is closer to become reality.

Finally we will take a look at some “close enough to real world” usage. HTTP router!

I’ll start (for real TDD/BDD experience) with Gemfile and test.

Feel free to make those tests green as a homework. Here’s my simple Rack implementation.

… composing and running tests…

OK, we have prototype now. Time to rewrite this using new pattern matching feature. I recommend you to try this on your own for real Ruby pattern matching experience. My simple implementation follows.

And finally we can check our new pattern matching based implementation status.

It works! Time to compare both implementations side to side. It can take some time to get comfortable reading case in statements effectively, but once you get better friends, you’ll get excited by the difference (at least I hope).

Even in this simple example, pattern matching based implementation is easier to read and to understand for me. Have you been battling huge incoming JSON payloads? Do you already see how pattern matching can be useful?

This is just start. Pattern matching allows much more than I was able to showcase in this article.

As you can see Ruby is not dead language. It is moving forward. Sometimes it’s successful and publicly well accepted move. Sometimes it is less successful and publicly not well accepted experimental feature removed before final release (sending my condolences to Ruby’s take on pipeline |> operator).

I hope this is start of new way of thinking about Ruby coding with advanced data structures. I'm pretty excited and looking forward! Thanks everyone involved in this new experimental feature.

Add a comment

Related posts:

Mobile Payment

We are writing to request your support and assistance with a recent proposal to implement a digital payment system in Syldavia through Pelican-mobile, the country’s largest mobile network operator…