I fail to see how having a function head helps me avoid ambiguity. On a different but related note, if Elixir really wanted to avoid ambiguity, it wouldn’t let something like this pass by with a mere warning:
defmodule MyTest do
def func(a, _), do: "I always match"
def func(a, b), do: "I never match!"
end
In the cases of ambiguity, I feel that this warning is more than sufficient and function heads really don’t server a purpose. Can someone point to a simple but useful example of how function heads help?
P.S. I’m also interested in the pull request that made this change. Maybe going through that discussion will help.
The reason is that default arguments are syntactic sugar around a ‘double’ definition:
def foo(a, b \\ "default") do
IO.puts({a, b})
end
# Desugars to:
def foo(a) do
foo(a, "default")
end
def foo(a, b) do
IO.puts({a, b})
end
This means that if you have multiple other function clauses that accept two arguments, it is unclear which one should be called by the automatically generated one-argument version. So to resolve this ambiguity, Elixir requires you to specify the default arguments as a separate (body-less) function head in these cases.
Try your own example in the console please. It won’t work.
** (CompileError) iex:4: definitions with multiple clauses and default values require a function head. Instead of:
def foo(:first_clause, b \\ :default) do ... end
def foo(:second_clause, b) do ... end
one should write:
def foo(a, b \\ :default)
def foo(:first_clause, b) do ... end
def foo(:second_clause, b) do ... end
def foo/3 has multiple clauses and defines defaults in a clause with a body
Is that comment intended for me? (sorry I can’t tell which comment is in reply to which on this forum). If so, the example in my original post was compiled and checked. The other one, with many clauses, was made up in response to Qqwy above. I’m not sure from where you’ve picked up the example.
As your example shows, there’s a clash. Function head helps, because we split argument expansion from the implementation clauses. So when you write a bodyless declaration:
The bodyless declaration took care of expanding arguments by providing implementations of foo/1 and foo/2.
Notice that at this point, foo/3 is not implemented. However, since default values are now taken care of, you can easily implement that function without worrying about defaults:
I know this is almost 2 years old, but this is the only post that I can find that explains this well…but I am wondering should def foo(a, b), do: foo(a, nil, nil) in your answer be def foo(a, b), do: foo(a, b, nil)?