Elixir: Anonymous Functions, Modules, and More

5 min

Elixir is a dynamic, general-purpose, functional programming language. It was created by José Valim, a developer with a background in Ruby, with the specific intent to utilize the scalability and maintainability features of the Erlang platform. Although not the most popular language out there, Elixir is beloved by its users. Companies such as Spotify, Discord, and Heroku have already adopted Elixir for its ease in building distributed, concurrent, and fault-tolerant systems.

Anonymous Functions, Modules, and More

Elixir also supports anonymous functions, which can be defined using the fn keyword or with the shorthand & syntax.

elixir
sum = fn a, b -> a + b end
IO.puts sum.(1, 2)

# 3
elixir
sum = &(&1 + &2)
IO.puts sum.(2,3)

# 5

Modules

Modules are used to organise named and private functions into a namespace. Here are some examples with public and private functions.

elixir
defmodule CoolStuff do
  def calculate(num1, num2) do
    IO.puts num1 + num2
  end
end

CoolStuff.calculate(1, 2)

defmodule Greet do
  def hello(name) do
    greeting(name)
  end

  defp greeting(name) do
    IO.puts "Hello" <> " " <> name
  end
end

Greet.hello("John")

Module Attributes

Used as constants throughout the module.

elixir
defmodule Greetings do
  @name "George"

  def hello(), do: "Hello #{@name}"
  def morning(), do: "Good Morning #{@name}"
  def night(), do: "Good night #{@name}"
end

Greetings.hello()

Module Documentation

Documentation can be attached to modules and functions.

elixir
defmodule Example do
  @moduledoc"""
  This is my module documentation
  """

  @doc"""
  This is my test function
  multiline comment and documentation.
  """

  def test() do
    "this is a test"
  end

  # This is a line comment
  def test2(), do: "nothing"
end

Structs

In Elixir, a struct is a data structure that provides an alternative to using maps or tuples for storing and manipulating related data.

elixir
defmodule User do
  defstruct [:name, :age]
end

u = %User{age: 20}
u.age

Alias

An alias is a way to create a shorthand for a module or a module's function.

elixir
defmodule AnotherModule do
  def another_function do
    IO.puts "Hello"
  end
end

defmodule MyModule do
  alias AnotherModule, as: Another

  def my_function do
    Another.another_function()
  end
end

MyModule.my_function()

Import

Import allows us to use functions from other modules directly.

elixir
defmodule ImportExample do
  import Math

  def import_sum(num1, num2) do
    sum(num1, num2)
  end
end

ImportExample.import_sum(1, 2)

We can use only to import specific functions, or except to exclude specific functions.

Function Arguments

Functions in Elixir can have default values for arguments.

elixir
defmodule Say do
  def hello(name, last_name, _greeting \ "Hello!") do
    "#{_greeting}! #{name} #{last_name}"
  end
end

Say.hello("John", "Barton")

Function Pattern Matching

Pattern matching is a key feature of Elixir.

elixir
defmodule Alphabet do
  def letter(:a), do: "a"
  def letter(:b), do: "b"
  def letter(:c), do: "c"
  def letter(letter), do: letter
end

Alphabet.letter(:a)
Alphabet.letter("other")

Useful modules and built in functions

Elixir comes with a range of built-in modules and functions.

elixir
Integer.to_string(1)
String.capitalize("a")
String.contains?("This is a string", "This")

fruits = ["banana", "apple", "orange"]

List.last(fruits)
List.to_string ["a", "b", "c"]

letters = %{"a" => "A", "b" => "B"}
Map.put(letters, "c", "C")

Enum.each(fruits, fn x -> IO.puts x end)

length fruits
to_string 1

Pipe Operator

The pipe operator, represented as |>, is a fundamental feature in the Elixir programming language. It is used for chaining functions together in a readable manner. The purpose of the pipe operator is to enhance code readability and enable a more fluent style of programming. When using the pipe operator, the result of the expression on the left is automatically inserted as the first argument of the function on the right.

elixir
string = " My String "

string
|> String.downcase()
|> String.trim()
|> String.split()
|> Enum.join("-")

IO.puts string

# "my-string"