Functions

Functions are small pieces of code that can be reused. They take inputs, called arguments, and return values or have side effects on other pieces of data. In elixir, there are three syntaxes we use for functions:

Example:

double = fn a -> a + a end

def double(a) do
  a + a
end

def double(a), do: a + a

These all have different utility in context.

Anonymous functions

In Elixir, we can create functions which are treated just like any other type. To create a function, we’ll use the keywords fn and end. For example, type the following in IEx:

iex> add = fn a, b -> a + b end
iex> is_function(add)
true

The anonymous function is now bound to the variable add. In order to actually execute our anonymous function, we’ll need to add a suffix of . to the variable. For example, to call the add/2 function, try the following:

iex> add.(2, 2) # 4

Functions in Modules

Modules are used to group related functions. When defining functions inside modules, we use the following syntax:

The keyword def is used:

defmodule Foo do
  def hashtag(word) do
    "#" <> word
  end
end

Foo.hashtag("elixir")

Inline functions

Note that we used the do ... end syntax for the block, but there’s also a shortcut syntax:

def hashtag(word), do: "#" <> word

Private Functions

If we want to create a private function that cannot be accessed publicly, we use the ‘defp` keyword.

defp add(a, b) do
  a + b
end

Pattern Matching with Functions.

Pattern matching becomes very useful when we use it with functions.

Take a look at the example below.

defmodule Social do
  def hashtag({:twitter, word}), do: "#" <> word <> " #twitterisgreat"

  def hashtag({:facebook, word}), do: "#" <> word <> " #facebookisgreat"
end

As you can see, we have two functions here with the exact same name. The question becomes - which function is executed? The function that gets executed is the one where data being passed in matched the arguments in the function signature.

This eliminates the need for us to use conditional logic in our functions. Copy and paste the module above, and then try the following:

Social.hashtag({:facebook, "elixir"})
Social.hashtag({:instagram, "elixir"})

What happened? When there’s no matching function in Elixir, you get a similar error to the other failed matches:

Social.hashtag({:instagram, "elixir"})
** (FunctionClauseError) no function clause matching in Social.hashtag/1
   iex:2: Social.hashtag({:instagram, "elixir"})

We received an error because there was no function signature that matched the arguments that had been passed in. To prevent triggering such an error, you can add a default case to your functions when pattern matching. In this case we will add one more function to our module.

defmodule Social do
  def hashtag({:twitter, word}), do: "#" <> word <> " #twitterisgreat"

  def hashtag({:facebook, word}), do: "#" <> word <> " #facebookisgreat"

  def hashtag({network , word}), do: "#" <> word <> " ##{network}isgreat"
end

This way, any network we pass in will match the last function, and we won’t see that error. Try it out:

iex(4)> Social.hashtag({:instagram, "elixir"})
"#elixir #instagramisgreat"

Order matters when defining functions. Notice we put the default case last. That’s because the patterns are matched in the order that they appear in the file. Since the default case will match whatever we pass in, we put it last, so the special cases have a chance to match.