This example here gives a warning that the second definition will never match join/2.
defmodule Concat3 do
def join(a, b) do
IO.puts "***First join"
a <> b
end
def join(a, b, sep \\ " ") do
IO.puts "***Second join"
a <> sep <> b
end
end
If we flip the definitions, we get an error:
defmodule Concat3 do
def join(a, b, sep \\ " ") do
IO.puts "***Second join"
a <> sep <> b
end
def join(a, b) do
IO.puts "***First join"
a <> b
end
end
Question: The fact these two definitions overlap is obvious. What is confusing to me is why it is an error in one case but a warning in another. There is something going on here that I am not understanding (and I do not have it pin pointed), but I would have expected it to be both warnings or both errors. What’s going on ?
Hi! It would be easier for us to help you understand this, if you’d give us the errors/warnings text as well.
Not everyone has access to an elixir compiler all the time, also the observed behaviour might be version dependant, therefore please also provide your elixir version.
cat warn.ex; elixir warn.ex
defmodule Concat3 do
def join(a, b) do
IO.puts "***First join"
a <> b
end
def join(a, b, sep \\ " ") do
IO.puts "***Second join"
a <> sep <> b
end
end
warning: this clause for join/2 cannot match because a previous clause at line 3 always matches
warn.ex:8
Error
cat error.ex ; elixir error.ex
defmodule Concat3 do
def join(a, b, sep \\ " ") do
IO.puts "***Second join"
a <> sep <> b
end
def join(a, b) do
IO.puts "***First join"
a <> b
end
end
** (CompileError) error.ex:8: def join/2 conflicts with defaults from join/3
error.ex:8: (module)
I‘d expect the difference to be that the conflict in the first case is caused by autogenerated code, while in the second case it‘s caused by code you wrote and therefore you need to fix.
From another angle: In the first case still both implementations are callable, even if the second function will only be callable with explicitly supplying the default. In the second example the latter function can never be called.
The pattern matching is attempted from top to bottom (order of definitions). So the first join definition is attempted at first, then the second one and so on.
Providing a default argument actually defines two functions:
defmodule Concat3 do
def join(a, b, sep \\ " ") do
IO.puts "***Second join"
a <> sep <> b
end
end
defines Concat3.join/3 and Concat3.join/2. Something like this:
defmodule Concat3 do
def join(a, b, sep) do
IO.puts "***Second join"
a <> sep <> b
end
def join(a, b) do
join(a, b, " ")
end
end
So when you’re trying to define a separate join(a, b) manually, the function can never be matched or creates a conflict.