Elixir Fundamentals: Functional Programming and OTP · Functional Elixir: Data, Pattern Matching and Functions
Hello, Elixir: Basic Types and Immutability
Run Elixir scripts and IEx, meet the basic types (integers, floats, atoms, strings, booleans, nil), string interpolation, and the rule that data never changes: you transform it into new data.
What you'll build
A small greeting and price script that uses atoms, strings, interpolation and arithmetic, and shows that "changing" a value really means creating a new one.
The idea
Elixir is a functional language that runs on the BEAM, the Erlang virtual machine built for telecom systems that must never go down. It's known for concurrency (millions of lightweight processes), fault tolerance, and the Phoenix web framework (with LiveView for real-time UIs).
Run code with:
iex # the interactive shell
elixir script.exs # run a script
mix new my_app # create a project (mix is the build tool)
Basic types: integers (any size), floats, atoms (named constants like :ok, :error; true, false and nil are atoms too), strings (UTF-8, double quotes, "#{expr}" interpolation), lists [1, 2], tuples {:ok, 1} and maps %{name: "Ana"}.
Immutability: data never changes in place. String.upcase(name) returns a new string; name is untouched. Variables can be rebound to new values, but the old value itself is never modified, which makes concurrent code safe by default.
IO.puts prints a string; IO.inspect prints any value in its literal form (great for debugging, and it returns the value so you can drop it into pipelines).
The code
name = "ana silva"
status = :active
price = 19.99
quantity = 3
IO.puts("Hello, #{name |> String.split() |> Enum.map(&String.capitalize/1) |> Enum.join(" ")}!")
IO.puts("Status: #{status}, is an atom: #{is_atom(status)}")
IO.puts("Total: #{Float.round(price * quantity, 2)}")
IO.puts("Integer division: #{div(7, 2)}, remainder: #{rem(7, 2)}, float division: #{7 / 2}")
IO.puts("Big integers are fine: #{2 ** 100}")
upper = String.upcase(name)
IO.puts("upper: #{upper}, original still: #{name}") # functions return new data
name = "ben" # rebinding points the name at a new value
IO.puts("rebound: #{name}")
IO.inspect({:ok, "saved"})
IO.inspect(%{name: "Ana", langs: ["Elixir", "Rust"]})
IO.inspect(String.length("héllo"), label: "characters")
IO.inspect(byte_size("héllo"), label: "bytes")
Output
Hello, Ana Silva!
Status: active, is an atom: true
Total: 59.97
Integer division: 3, remainder: 1, float division: 3.5
Big integers are fine: 1267650600228229401496703205376
upper: ANA SILVA, original still: ana silva
rebound: ben
{:ok, "saved"}
%{name: "Ana", langs: ["Elixir", "Rust"]}
characters: 5
bytes: 6Run this on your computer — see “Get Started” for setup.
Common mistakes
- Single quotes.
'hello'is a charlist (a list of code points), not a string; use double quotes. - Expecting mutation.
String.upcase(name)alone does nothing visible; bind or pipe the result. lengthvsbyte_size. Strings are UTF-8;String.lengthcounts characters,byte_sizecounts bytes./returns a float. Usediv/2andrem/2for integers.
Key points
- Elixir runs on the BEAM: concurrency and fault tolerance built in.
- Atoms (
:ok), strings with#{}interpolation, lists, tuples, maps. - Data is immutable; functions return new values; variables can be rebound.
IO.putsfor strings,IO.inspectfor any value (withlabel:).
Further reading: Elixir getting started: basic types.
Practice questions
What does immutability mean in Elixir?
Answer
Data structures are never modified in place. Functions return new values; a variable can be rebound to a new value, but the original data is unchanged, which makes sharing data between concurrent processes safe.
What is an atom in Elixir?
Answer
A constant whose value is its own name, like :ok or :error. Atoms are used as tags (e.g. {:ok, value}), map keys and module names; true, false and nil are atoms too.
Open in the app to mark lessons complete, take notes and track your progress.