Order of precedence in string matching

Hello there,

I know that:

str  = "_forum"
"elixir" <> str

But the following fails:

 "elixir" <> str = "_forum"
** (MatchError) no match of right hand side value: "_forum"

And the following works:

iex(1)> "elixir" <> str = "elixir_forum"
iex(2)> str

This is making my head spin. Please, can someone help me with a logical breakdown of how this matching, binding, and concatenation operation works and the rationale behind the ordering?

The key is to recognise that = is really a match operator, with the side affect of binding the variable.


  • str = "_forum" matches and binds. There is no pattern so anything will bind.
  • "elixir" <> str has no pattern matching (there’s no left and right), its just a call to the function Kernel.<>/2 with the parameters "elixir" and str
  • "elixir" <> str = "_forum" is a pattern match (there is a left and right around the match operator =. It can’t match because "_forum" cannot match "elixir" <> str
  • "elixir" <> str = "elixir_forum" matches just fine as I think you may have worked out by now

Hope that’s sufficiently clear, if not ask away


Thank you for your swift and kind response.

I did not work it out but saw it in a video tut. My desire is to understand the underlying concept of the language rather than memorizing interesting code snippets.

So if I get you right, the following are analogous:

"elixir" <> str = "elixir_forum"
["elixir", str] = ["elixir", "forum"]

Not really analagous, but but they are both matches.

  • "elixir" <> str = "elixir_forum" is a binary match (thats indicated by the <>). Basically it can be read as "match a string that starts with elixir and bind anything that comes after that to str. str end up being bound to "_forum"
  • ["elixir", str] = ["elixir", "forum"] is asking the question: are both sides of the match operator (the =) of the same shape? In this case, yes - they are both lists with 2 elements. Then do the elements match? For the first element, yes, "elixir" == "elixir. And the second element binds "forum" to str.
"elixir" <> str = "elixir_forum"

Is exactly the same as:

<<"elixir", str::binary>> = "elixir_forum"

Thank you @kip and @hauleth, putting your answers together make it clearer.