Senger CodeLab 🚀

Why are there two kinds of functions in Elixir

September 29, 2026

📂 Categories: Programming
Why are there two kinds of functions in Elixir

Elixir, a dynamic, functional language built on the Erlang VM, presents a unique approach to functions. Why are there two kinds of functions in Elixir? This seemingly simple question unveils a core aspect of Elixir’s design, impacting how code is organized, executed, and optimized. Understanding this distinction is crucial for writing efficient, maintainable, and idiomatic Elixir code. This exploration delves into the “why” behind Elixir’s dual function system, clarifying the differences between named functions and anonymous functions, and showcasing their practical applications.

Named Functions: The Building Blocks of Modules

Named functions are the cornerstone of Elixir’s modular design. They reside within modules, providing structure and organization to your code. Defined using the def keyword, these functions are called by their name and arity (the number of arguments they accept). This explicit naming and modular structure promote code clarity and reusability.

For instance, within a module named Math, you might define a function called add/2 (indicating it takes two arguments):

defmodule Math do def add(x, y), do: x + y end 

This named function is easily called from other parts of your application using Math.add(2, 3).

Anonymous Functions: Flexible and Concise

Anonymous functions, defined using the fn...end syntax, offer a more flexible and concise way to express computations. Unlike named functions, they don’t belong to a specific module and are often used for short, self-contained operations. This makes them ideal for passing as arguments to higher-order functions like Enum.map/2 and Enum.filter/2, enabling powerful functional programming paradigms.

An example of an anonymous function that doubles a number:

double = fn x -> x  2 end double.(5) Returns 10 

Their concise syntax and ability to be passed around like data make anonymous functions a powerful tool in Elixir.

The Power of Pattern Matching

Both named and anonymous functions in Elixir leverage pattern matching, a powerful mechanism for controlling function execution based on the shape and value of arguments. This elegant approach simplifies code and improves readability. In named functions within modules, pattern matching is used to define multiple function clauses with different argument patterns.

defmodule Math do def multiply(x, 0), do: 0 def multiply(x, y), do: x  y end 

Here, multiply/2 has two clauses. The first matches when the second argument is 0, the second handles all other cases. This targeted matching allows for concise and expressive code.

Metaprogramming and Macros: Extending the Language

Elixir’s macro system allows developers to extend the language itself. Macros operate on the Abstract Syntax Tree (AST) of the code, enabling powerful code transformations. While not directly a “kind” of function, macros leverage the function definition syntax and are integral to understanding Elixir’s flexibility. They are often used to define new control flow structures and generate boilerplate code, significantly enhancing developer productivity.

  • Named functions provide structure and are called by name.
  • Anonymous functions are flexible, passed as arguments, and used for concise operations.
  1. Define the function.
  2. Call the function with appropriate arguments.
  3. Utilize pattern matching for efficient conditional logic.

For further exploration of functional programming concepts, resources like Elixir’s official documentation and Programming Elixir 1.6 by Dave Thomas offer valuable insights. Consider also exploring resources on functional programming paradigms.

Featured Snippet: The two types of functions in Elixir, named and anonymous, offer distinct advantages. Named functions, residing within modules, provide structure and are called by their name and arity. Anonymous functions, defined using fn...end, are flexible and concise, often used in higher-order functions and closures.

[Infographic Placeholder: Illustrating the differences between named and anonymous functions, and how they interact with modules and higher-order functions.]

By understanding the strengths of each function type, Elixir developers can write more elegant, maintainable, and efficient code. Experimenting with both types in different scenarios is crucial for mastering Elixir’s functional programming paradigm. Dive into some Elixir code today and explore the power of these fundamental building blocks. Check out more resources on our blog.

Frequently Asked Questions

Q: Can anonymous functions be recursive?

A: Yes, anonymous functions can be recursive, but they require explicit self-referencing using a variable.

The dual function system, coupled with powerful features like pattern matching and macros, contributes significantly to Elixir’s elegance and power. Embracing these concepts is key to unlocking the full potential of Elixir for building robust and scalable applications. Continue learning about pattern matching, macros, and the nuances of Elixir’s functional approach to further refine your skills.

Question & Answer :
I’m learning Elixir and wonder why it has two types of function definitions:

  • functions defined in a module with def, called using myfunction(param1, param2)
  • anonymous functions defined with fn, called using myfn.(param1, param2)

Only the second kind of function seems to be a first-class object and can be passed as a parameter to other functions. A function defined in a module needs to be wrapped in a fn. There’s some syntactic sugar which looks like otherfunction(&myfunction(&1, &2)) in order to make that easy, but why is it necessary in the first place? Why can’t we just do otherfunction(myfunction))? Is it only to allow calling module functions without parenthesis like in Ruby? It seems to have inherited this characteristic from Erlang which also has module functions and funs, so does it actually comes from how the Erlang VM works internally?

It there any benefit having two types of functions and converting from one type to another in order to pass them to other functions? Is there a benefit having two different notations to call functions?

Just to clarify the naming, they are both functions. One is a named function and the other is an anonymous one. But you are right, they work somewhat differently and I am going to illustrate why they work like that.

Let’s start with the second, fn. fn is a closure, similar to a lambda in Ruby. We can create it as follows:

x = 1 fun = fn y -> x + y end fun.(2) #=> 3 

A function can have multiple clauses too:

x = 1 fun = fn y when y < 0 -> x - y y -> x + y end fun.(2) #=> 3 fun.(-2) #=> 3 

Now, let’s try something different. Let’s try to define different clauses expecting a different number of arguments:

fn x, y -> x + y x -> x end ** (SyntaxError) cannot mix clauses with different arities in function definition 

Oh no! We get an error! We cannot mix clauses that expect a different number of arguments. A function always has a fixed arity.

Now, let’s talk about the named functions:

def hello(x, y) do x + y end 

As expected, they have a name and they can also receive some arguments. However, they are not closures:

x = 1 def hello(y) do x + y end 

This code will fail to compile because every time you see a def, you get an empty variable scope. That is an important difference between them. I particularly like the fact that each named function starts with a clean slate and you don’t get the variables of different scopes all mixed up together. You have a clear boundary.

We could retrieve the named hello function above as an anonymous function. You mentioned it yourself:

other_function(&hello(&1)) 

And then you asked, why I cannot simply pass it as hello as in other languages? That’s because functions in Elixir are identified by name and arity. So a function that expects two arguments is a different function than one that expects three, even if they had the same name. So if we simply passed hello, we would have no idea which hello you actually meant. The one with two, three or four arguments? This is exactly the same reason why we can’t create an anonymous function with clauses with different arities.

Since Elixir v0.10.1, we have a syntax to capture named functions:

&hello/1 

That will capture the local named function hello with arity 1. Throughout the language and its documentation, it is very common to identify functions in this hello/1 syntax.

This is also why Elixir uses a dot for calling anonymous functions. Since you can’t simply pass hello around as a function, instead you need to explicitly capture it, there is a natural distinction between named and anonymous functions and a distinct syntax for calling each makes everything a bit more explicit (Lispers would be familiar with this due to the Lisp 1 vs. Lisp 2 discussion).

Overall, those are the reasons why we have two functions and why they behave differently.