# Functions call with underscore and assignment

While watching Jose Valim doing advent of code 2021, I noticed him called function like this

``````def test(a) do
IO.puts(a)
end
test(_a = 5)
``````

What is the purpose of using _a = 5 instead of 5? Is there a name for this technique?

useful to not get lost when you have mutiple arguments, eg

``````iex(1)> foo = fn a,b,c,d -> {a,b,c,d} end
#Function<41.65746770/4 in :erl_eval.expr/5>
iex(2)> foo.(_a=1, _b=2, _c=3, _d=4)
{1, 2, 3, 4}
``````

Note that this is different to eg pythons named arguments, where the names really have a meaning.
in elixir its just to help read the code and has no meaning.

``````iex(3)> foo.(_banana1=1, _banana2=2, _banana3=3, _banana4=4)
{1, 2, 3, 4}
``````

You could also do

``````iex(4)> foo.(a=1, b=2, c=3, d=4)
{1, 2, 3, 4}
``````

But’ll get a warning, therefore the `_`
But you’ll (re)bind the variables which is most likely not what you want.

In some cases, you don’t care about a particular value in a pattern. It is a common practice to bind those values to the underscore, `_` . For example, if only the head of the list matters to us, we can assign the tail to underscore:

3 Likes

nice trick!

Nice one too. I didn’t know you could define variables in function calls.

1 Like

Actually, I also did not know that.
I thought you’d get an `unused variable` warning, but indeed:

``````defmodule Temp do
def foo(a, b, c, d), do: IO.inspect({a, b, c, d}, label: :in_foo)

def bar() do
foo(a=1, b=2, c=3, d=4)
IO.inspect({a, b, c, d}, label: :after_foo)
end
end
``````
``````iex(11)> Temp.bar
in_foo: {1, 2, 3, 4}
after_foo: {1, 2, 3, 4}
{1, 2, 3, 4}
``````

So the `_` is used here to hint, that the variable should be ignored.

But still, you’ll get the same result when changing the variable names in the call:

``````def bar() do
foo(k=1, l=2, m=3, n=4)
IO.inspect({k, l, m, n}, label: :after_foo)
end
``````

while in python for example:

``````>>> def foo(a, b):
...    print(f"first {a} then {b}")
...
>>> foo(1,2)
first 1 then 2
>>> foo(a=1,b=2)
first 1 then 2
>>> foo(b=1,a=2)
first 2 then 1
>>> foo(c=1,d=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'c'
``````
1 Like