The Basics of Functions: Named and Anonymous

There are multiple ways to define a function in elixir, before doing that let me describe what a function does.

Functions are the backbone of elixir, what they do is get input data, transform it, and output new data. Ideally each function should do one transformation only (Single Responsibility Principle).

Named functions

These have to be defined inside a module like:

defmodule Cache do
  def hello do
    :world
  end
end

Note: In elixir you don’t have to write a return statement, the value of the last expression in a function is the returned value.(if no value is returned then functions return ‘nil’ by default)

Quiz: Why did we get an ArgumentError?

How to define a named function in one line:

defmodule Cache do

  def hi(name),  do: "hi " <> name

end

Notice: the coma and the semicolon.

Anonymous functions

These are really easy to define:

fn (a, b) -> a + b end 

fn -> :world end

fn a, b -> a + b end

In the first function, “a” and “b” are the input values and the output is the result of a + b

The second function is equivalent to the ‘hello’ function above.

The third function is the same as the first, but I believe the first one looks more clear with the parentheses.

We can assign anonymous functions to variables, and call them with the variable name. Let’s do that with the second function.

So all we had to do was:

helloanon = fn -> :world end
hellanono.()

The first time we try to call “helloanon” we get the same value:

#Function<20.128620087/0 in :erl_eval.expr/5>,

that we got when we declared and assigned the variable.

This happens because “helloanon” is not a function, is a variable that references the anonymous function. So we can not call “helloanon” as we did with ‘Cache.hello’ function previously.

In other languages it would make sense to call: helloanon(), right?

But that doesn’t work either, we have to call it with a dot + parentheses: .()

The reason for this is because in elixir we have a namespace for variables and a different namespace for functions. So you can have a variable and a function with the same name! And what happens if we have a variable pointing to a function and a function with the same name you may ask, well that’s what the .() notation is there for:

To differentiate calling a named function from a referenced function(anonymous).

Scope

Unlike named functions, anonymous functions are scoped from the context from which we created them. (This means we can use environment and variable values from the moment when we created the anonymous function). In a sense named functions are isolated from their calling environment.(We have to give them all context as parameter values)

To illustrate this better consider the following module:

defmodule Calculator do

  def duplicate(a), do: 2 * a

end

and watch this:

As you can see even when we change the value of ‘a’ the anonymous function sticks to the value ‘a’ had when we created it.

So in both type of functions you can pass parameters but only on anonymous ones we can use context variables without having to pass them.

Now these two functions are not equivalent since, the ‘Calculator.duplicate’ has 1 argument and ‘duplicate’ doesn’t have any. The point wasn’t to make them equivalent, the point was to illustrate how environment variables affect anonymous function if we use them.

If you’re not using environment values an anonymous function will act as a named one if they have the same parameters, body, etc.

Thanks to the following posts: Why do we use a dot to call a function? , Anonymous functions, the dot, and parameters both from the elixir forum.

The next post is on a very important property of elixir functions: Arity


Leave a Reply

Your email address will not be published. Required fields are marked *