When I run the following Elixir script, it prints out {"K", "Y", "L"}
.
defmodule MyMod do
def make_tuple(a \\ "X", b \\ "Y", c) do
{a, b, c}
end
end
IO.inspect(MyMod.make_tuple("K", "L"))
Why doesn't it output {"X", "K", "L"}
? What is the mechanism behind this behavior?
It's not possible to skip it, but you can pass the default argument using ReflectionFunction .
Which is the correct condition for the default arguments? Explanation: The default arguments must be declared at last in the argument list. This is to ensure that the arguments doesn't create ambiguity.
A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the caller of the function doesn't provide a value for the argument with a default value.
Kotlin Default arguments – The arguments which need not specify explicitly while calling a function are called default arguments. If the function is called without passing arguments then the default arguments are used as function parameters.
The reason for this behavior is that Elixir pattern-matches the arguments that a function is called with against the arity the function is defined with. Let’s think about how the data looks when it arrives to Greeter1.hello/1:
In Elixir and many functional languages, functions are first class citizens. We will learn about the types of functions in Elixir, what makes them different, and how to use them. Just as the name implies, an anonymous function has no name. As we saw in the Enum lesson, these are frequently passed to other functions.
Once Elixir has matched a function any existing guards will be tested. In the following example we have two functions with the same signature, we rely on guards to determine which to use based on the argument’s type:
You are correct: Elixir uses any "excess" arguments provided to override a function's default values for some or all of its parameters, filled from left to right. My understanding of this came from the Programming Elixir 1.6 book by Dave Thomas.
The trick is that for functions with default arguments, the compiler actually generates multiple functions. A function defined like this:
defmodule Example do
def func(p1, p2 \\ 2, p3 \\ 3, p4) do
IO.inspect [p1, p2, p3, p4]
end
end
Actually gets compiled down to a module that looks something like this:
defmodule Example do
def func(p1, p4) do
func(p1, 2, 3, p4)
end
def func(p1, p2, p4) do
func(p1, p2, 3, p4)
end
def func(p1, p2, p3, p4) do
IO.inspect [p1, p2, p3, p4]
end
end
By the way, you can see this by using a module's "magic" module_info/0
function, e.g. Example.module_info()
.
Calling your functions with some sample values will help you understand how they are interpreted, and there may be a few surprises.
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"]
It may be a bit easier to see this behavior with a function like this:
def func(p1 \\ 1, p2 \\ 2) do
IO.inspect [p1, p2]
end
And calling it with only 1 argument provided. It will use the provided argument on the left side; the default on the right still gets used:
func("a") # => ["a", 2]
I agree that things do get confusing when a function has optional arguments that aren't at the end of the argument list.
Just from experimenting with it a bit, it seems like it assigns the arguments from the left. So in this case:
defmodule MyMod do
def make_tuple(a \\ "X", b, c \\ "Y", d) do
{a, b, c, d}
end
end
IO.inspect(MyMod.make_tuple(1, 2, 3))
You get {1, 2, "Y", 3}
- this is a "left-most" interpretation of the arguments provided. This leads to a situation where if you add an argument "at the end" it changes the meaning of the previous arguments, and (I assume) is the reason why people usually avoid having optional arguments that are not at the end of the argument list.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With