Day 1 of 5
⏱ ~60 minutes
Elixir in 5 Days — Day 1

Elixir Fundamentals & Pattern Matching

Elixir is a functional, concurrent language built on the Erlang VM (BEAM). It powers WhatsApp (2 million connections per server), Discord, and Heroku. Today you learn Elixir's syntax, immutable data, and the pattern matching that makes it expressive.

The BEAM Virtual Machine

Elixir runs on BEAM — the Erlang VM built by Ericsson in the 1980s for telecom systems requiring 99.9999999% (nine-nines) uptime. BEAM runs millions of lightweight processes (not OS threads), each isolated with its own memory. A crashed process does not bring down others. This architecture makes Elixir naturally fault-tolerant and horizontally scalable — the same properties that attracted WhatsApp and Discord.

Basic Types and Immutability

Elixir types: integers, floats, booleans, atoms (:ok, :error, :hello), strings (UTF-8 binaries), lists [1,2,3], tuples {1,2,3}, maps %{key: value}, and nil. All data is immutable — rebinding a variable creates a new binding, it does not mutate the old value. Atoms are constants whose name is their value; :ok and :error are the most common return value conventions.

Pattern Matching

= in Elixir is the match operator, not assignment. '3 = 3' succeeds; '3 = 4' raises MatchError. '{:ok, value} = {:ok, 42}' binds value to 42. '[head | tail] = [1,2,3]' binds head=1, tail=[2,3]. Pattern matching in function clauses, case expressions, and receive blocks is the primary control flow mechanism. The _ wildcard matches anything without binding.

elixir
# Basic pattern matching
{:ok, value} = {:ok, 42}
IO.puts(value)  # 42

# Function with multiple clauses
defmodule Math do
  def factorial(0), do: 1
  def factorial(n) when n > 0, do: n * factorial(n - 1)

  def fib(0), do: 0
  def fib(1), do: 1
  def fib(n), do: fib(n-1) + fib(n-2)
end

IO.puts Math.factorial(10)  # 3628800
IO.puts Math.fib(10)        # 55

# Case expression
result = {:error, "not found"}
message = case result do
  {:ok, val}  -> "Success: #{val}"
  {:error, e} -> "Error: #{e}"
  _           -> "Unknown"
end
IO.puts message  # Error: not found

# Pipe operator
"  hello world  "
|> String.trim()
|> String.upcase()
|> String.split(" ")
|> Enum.join("-")
|> IO.puts()  # HELLO-WORLD
💡
The pipe operator |> passes the result of the left expression as the first argument to the right function. It makes data transformation pipelines read left-to-right, matching how you think about the transformation.
📝 Day 1 Exercise
Pattern Matching Practice
  1. Install Elixir via asdf: asdf plugin add elixir && asdf install elixir latest
  2. Open iex (interactive Elixir) and try pattern matching: {a, b} = {1, 2}
  3. Write a function fizzbuzz/1 using pattern matching on {rem(n,3), rem(n,5)}
  4. Write a recursive list_length/1 using pattern matching on empty vs head|tail
  5. Chain 5 transformations on a list using the pipe operator

Day 1 Summary

  • BEAM provides isolated lightweight processes for fault-tolerant concurrency
  • = is the match operator; it binds variables or raises MatchError
  • Function clauses with pattern matching replace if/else chains
  • Guards (when) add boolean conditions to pattern matches
  • The |> pipe operator chains function calls left-to-right
Challenge

Write an Elixir module that implements a simple stack using a list and pattern matching: push/2, pop/1, peek/1, size/1. Each function should return {:ok, result} or {:error, reason} tuples.

Finished this lesson?