This is a example on pattern matching.
Given the Map/Hash input:
input = %{name: "Alice Foo", points: 100, email: "alicefoo@myemail.com"}
The goal is to determine the user rank, by its points:
0..50
-> Starter50..200
-> Member>200
-> Veteran
The code in Elixir using pattern matching:
defmodule Rank do
@moduledoc """
Offers means to perform user ranking computations.
"""
@typedoc """
A user rank.
"""
@type rank :: :starter | :member | :veteran
@doc """
Finds the rank of a given user.
"""
@spec find(%{points: integer()}) :: rank()
def find(%{points: n}) when n <= 50, do: :starter
def find(%{points: n}) when n <= 200, do: :member
def find(_user), do: :veteran
end
Here's how you use it:
iex(1)> Rank.find(input)
:member
The same code in Ruby:
class Rank
# Offer means to perform ranking computations.
# Finds the rank of a given user.
def self.find(user)
case user[:points]
when 0..50
:starter
when 50..200
:member
else
:veteran
end
end
end
And running it:
irb(main):001:0> Rank.find(input)
=> :member
Patter matching makes the code more elegant, expressive and easier to read.
This is simply a bad example to demonstrate the power of pattern matching in Elixir.
Here's an example of argument overloading...
Pattern matching gets even better when you want to assert the "shape" of a deeply nested object/struct, whereas in Ruby, you have to do it with multiple
if
statements with (maybe complex) boolean logic.Most people I know, including myself, say the thing they miss most when going back to Ruby is pattern matching. It's absolutely amazing and elegant once you get used to it.
Further, in the Elixir example, you get some kind of static analysis from that code; you'll get warnings if you call
get_name
with something other than a User, Post, or integer (usually displayed right in your editor of choice as you type it). You get exactly zero of that with Ruby.