Difference between `%Struct{} = struct` and `struct = %Struct{}` in defs

I noticed my function definitions had instances of def my_fun(struct = %Struct{field: field}) instead of the other way around (def my_fun(%Struct{field: field} = struct)), which seems more common.

My question is whether the order matters and why & how this works :slight_smile:


In this case order does not matter, the entire thing becomes a, an Erlang parlance, MatchSpec, it just makes sure the whole thing is matched out and returns a set of bindings to some of the internal data. :slight_smile:


Hmmmmm I see, thanks


There is no difference. Basically the = defines an alias where both sides are patterns which must match. In this case both the struct and the variable must match. It is typically used for maps, structs and records where you want to test the contents and get a reference to the whole but it is legal anywhere in a pattern. For example try this in the shell

iex(4)> [:a = x | [_] = y] = [:a,:b]
[:a, :b]
iex(5)> y
iex(6)> x

It’s first worth mentioning that a return value of a simple pattern match expression (pat = expression) is the value of the right-hand side expression:

iex> {_, _} = {:ok, 42}
{:ok, 42}

Pattern matches can be chained so pat1 = pat2 = term is equivalent to pat1 = (pat2 = term), and since the result of a match expression is the term itself, you’re just consecutively matching from right to left. The matching order can easily be proved in iex:

iex> ^a = a = 42

iex> b = ^b = 42
** (CompileError) iex:2: unbound variable ^b

The second match can’t work because chaining is right-associative, so ^b = 42 is done before b is bound and the compiler complains.

When it comes to your example, the order doesn’t matter. In fact, in most cases I’ve used/seen in practice I don’t think the order mattered. When chaining matches in function heads, or e.g. case clauses, I use the %Struct{...} = struct style for a couple of reasons:

  1. IIRC, I’ve seen this in first Erlang books and other resources I read when I was learning.
  2. As you said, it generally seems to be a prevalent convention.
  3. That style puts more emphasis on what I’m trying to branch on (%Struct{...}), which I think is a slightly better assistance for readers.

Thanks guys, I just didn’t understand how it relates to Kernel.SpecialForms.= (where the order does matter) but I think I understand now:

iex> x = 1
iex> 2 = y
** (CompileError) ...

Both match from right to left, as @sasajuric showed so the second example causes an error.

def my_fun(pat1 = pat2) do
  # ...

Here the order doesn't matter cause when evaluated the complete expression becomes this (or so I think):

pat1 = pat2 = value

So in any case (function invocation or not), the pattern matches from right to left. When the function is actually invoked the full expression becomes `pat1 = pat2 = value` so it happens to not make a difference and it's only a matter of taste / conventions.


Precisely, when doing a binding expression (the iex> 2 = y in your example) the order matters like @sasajuric stated, but when doing a matchspec (the def my_fun(pat1 = pat2) do example) it just defines matchers, like @rvirding stated. :slight_smile:

You can actually craft matchspec’s directly and use them for various purposes, especially with mnesia lookups (I wish we had functionality in Ecto to use them). :slight_smile:

1 Like