Can someone please explain it why is that not working?
When you call a function, elixir starts with the first function clause in the definition and tries to match the arguments specified in the function call to the parameters in the function definition. If there's no match, elixir then tries the next function clause. When a match is found, the corresponding function body executes. If none of the function clauses match, then you get a function_clause error.
Let's go through an example. If you write:
def go({1, 2}, :cat) do
IO.puts "I must have matched the function call."
end
then you can call that function like this:
iex(2)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok
But, if you try:
ex(3)> A.go("hello", 10)
** (FunctionClauseError) no function clause matching in A.go/2
The following arguments were given to A.go/2:
# 1
"hello"
# 2
10
a.ex:2: A.go/2
You get a function clause error because no function clause for the definition of go()
matches the function call:
function call: A.go("hello", 10)
| |
{1,2} = "hello | | :cat = 10
V V
function def: def go({1, 2}, :cat) do
The only argument in the go()
function call that can match the tuple {1, 2}
in the function definition is the tuple {1, 2}
, and the only argument in the function call that can match the atom :cat
in the function definition is the atom :cat
.
However, variables in a function definition match ANYTHING. Some examples of legal variable names are: x
, y
, _x
and _
. So, if you define go()
like this:
def go(_x, _y) do
IO.puts "I must have matched the function call."
end
then both function calls will match:
iex(3)> c "a.ex"
warning: redefining module A (current version defined in memory)
a.ex:1
[A]
iex(4)> A.go("hello", 10)
I must have matched the function call.
:ok
iex(5)> A.go({1, 2}, :cat)
I must have matched the function call.
:ok
If you add a second function clause to the go() definition:
def go(_x, _y) do
IO.puts "I must have matched the function call."
end
def go(_, _) do
IO.puts "I will never match"
end
the first function clause will still match any two arguments, and because that's the case, the second function clause will never execute--so the compiler gives you a warning, which is equivalent to:
Wtf? Why did you scribble all that junk in the second function clause
when it will never match and therefore never execute?! Get a grip!
Things get a little trickier when you do pattern matching in the function definition, for instance:
def go(%{a: val}=map, x) do
See here for how that works.