Introduction to Programming in Elixir

Elixir is a dynamic, functional programming language built on the Erlang VM (BEAM). It is designed for building scalable and maintainable applications, particularly for distributed and concurrent systems. Elixir combines the productivity of modern languages with the robustness of Erlang, making it a great choice for web development, real-time systems, and more.

This guide will introduce you to the fundamentals of Elixir programming, helping you write clean, efficient, and concurrent code.


Table of Contents

  1. What is Elixir?
  2. Setting Up Your Environment
  3. Basic Syntax and Data Types
  4. Pattern Matching
  5. Functions
  6. Modules and Structs
  7. Collections
  8. Concurrency with Processes
  9. Error Handling
  10. Metaprogramming with Macros

What is Elixir?

Elixir is a functional programming language that runs on the Erlang VM. It is known for its scalability, fault tolerance, and concurrency model.

# Example: Your first Elixir program
IO.puts("Hello, Elixir Programming!")

Setting Up Your Environment

To write and run Elixir programs, you need to install Elixir on your system. Follow the instructions on the official Elixir website.

# Example: Running an Elixir script
elixir main.exs

Basic Syntax and Data Types

Elixir is a dynamically typed language with a clean and expressive syntax. Common data types include integers, floats, atoms, strings, and lists.

# Example: Declaring variables
age = 25
height = 5.9
name = "Alice"
is_student = true

IO.puts("Name: #{name}, Age: #{age}, Height: #{height}")

Pattern Matching

Pattern matching is a core feature of Elixir, allowing you to destructure data and bind variables in a concise way.

# Example: Pattern matching
{a, b} = {1, 2}
IO.puts("a: #{a}, b: #{b}") # a: 1, b: 2

Functions

Functions in Elixir are first-class citizens and can be defined using the def keyword. Elixir also supports anonymous functions.

# Example: Function
defmodule Math do
  def add(a, b) do
    a + b
  end
end

result = Math.add(5, 10)
IO.puts("Result: #{result}") # 15

Modules and Structs

Modules are used to organize functions, and structs are used to define custom data types.

# Example: Module and Struct
defmodule Person do
  defstruct name: "", age: 0

  def display(%Person{name: name, age: age}) do
    IO.puts("Name: #{name}, Age: #{age}")
  end
end

person = %Person{name: "Alice", age: 25}
Person.display(person)

Collections

Elixir provides powerful collection types like lists, tuples, and maps for storing and manipulating data.

# Example: List
fruits = ["Apple", "Banana", "Orange"]
Enum.each(fruits, fn fruit -> IO.puts(fruit) end)

Concurrency with Processes

Elixir’s concurrency model is based on lightweight processes, which are isolated and communicate via message passing.

# Example: Spawning a process
pid = spawn(fn ->
  receive do
    {:greet, name} -> IO.puts("Hello, #{name}!")
  end
end)

send(pid, {:greet, "Alice"})

Error Handling

Elixir uses the try, catch, and rescue constructs for error handling, but it encourages a “let it crash” philosophy for fault-tolerant systems.

# Example: Error handling
try do
  raise "Something went wrong"
rescue
  e in RuntimeError -> IO.puts("Error: #{e.message}")
end

Metaprogramming with Macros

Elixir supports metaprogramming through macros, allowing you to generate code at compile time.

# Example: Macro
defmodule MyMacro do
  defmacro say_hello do
    quote do
      IO.puts("Hello from a macro!")
    end
  end
end

defmodule Main do
  require MyMacro
  MyMacro.say_hello()
end