When you define a named function, you can give a default value to any of its parameters by using the syntax param \\ value. When you call a function that is defined with default parameters, Elixir compares the number of arguments you are passing with the number of required parameters for the function. If you’re passing fewer arguments than the number of required parameters, then there’s no match. If the two numbers are equal, then the required parameters take the values of the passed arguments, and the other parameters take their default values. If the count of passed arguments is greater than the number of required parameters, Elixir uses the excess to override the default values of some or all parameters. Parameters are matched left to right.
| defmodule Example do |
| def func(p1, p2 \\ 2, p3 \\ 3, p4) do |
| IO.inspect [p1, p2, p3, p4] |
| end |
| end |
| |
| Example.func("a", "b") # => ["a",2,3,"b"] |
| Example.func("a", "b", "c") # => ["a","b",3,"c"] |
| Example.func("a", "b", "c", "d") # => ["a","b","c","d"] |
Default arguments can behave surprisingly when Elixir does pattern matching. For example, compile the following:
| def func(p1, p2 \\ 2, p3 \\ 3, p4) do |
| IO.inspect [p1, p2, p3, p4] |
| end |
| |
| def func(p1, p2) do |
| IO.inspect [p1, p2] |
| end |
and you’ll get this error:
| ** (CompileError) default_params.exs:7: def func/2 conflicts with |
| defaults from def func/4 |
That’s because the first function definition (with the default parameters) matches any call with two, three, or four arguments.
There’s one more thing with default parameters. Here’s a function with multiple heads that also has a default parameter:
| defmodule DefaultParams1 do |
| |
| def func(p1, p2 \\ 123) do |
| IO.inspect [p1, p2] |
| end |
| |
| def func(p1, 99) do |
| IO.puts "you said 99" |
| end |
| |
| end |
If you compile this, you’ll get an error:
| warning: definitions with multiple clauses and default values require a |
| function head. Instead of this: |
| |
| def foo(:first_clause, b \\ :default) do ... end |
| def foo(:second_clause, b) do ... end |
| |
| one should write this: |
| |
| def foo(a, b \\ :default) |
| def foo(:first_clause, b) do ... end |
| def foo(:second_clause, b) do ... end |
| |
| def func/2 has multiple clauses and defines defaults in a clause with a body |
| code/mm/default_params1.exs:8 |
| |
| warning: variable p1 is unused |
| code/mm/default_params1.exs:8 |
| |
| warning: this clause cannot match because a previous clause at |
| line 4 always matches code/mm/default_params1.exs:8 |
The intent is to reduce confusion that can arise with defaults. Add a function head with no body that contains the default parameters, and use regular parameters for the rest. The defaults will apply to all calls to the function.
| defmodule Params do |
| |
| def func(p1, p2 \\ 123) |
| |
| def func(p1, p2) when is_list(p1) do |
| "You said #{p2} with a list" |
| end |
| |
| def func(p1, p2) do |
| "You passed in #{p1} and #{p2}" |
| end |
| |
| end |
| |
| IO.puts Params.func(99) # You passed in 99 and 123 |
| IO.puts Params.func(99, "cat") # You passed in 99 and cat |
| IO.puts Params.func([99]) # You said 123 with a list |
| IO.puts Params.func([99], "dog") # You said dog with a list |