🚀 Elixir Introduction
🎯 Complete Definition
Elixir is a dynamic, functional language designed for building scalable and maintainable applications. It runs on the Erlang VM (BEAM), known for low‑latency, distributed, and fault‑tolerant systems. Created by José Valim in 2012, Elixir combines Ruby‑like syntax with Erlang’s industrial‑grade capabilities. It embraces immutability, pure functions, and the actor model for concurrency.
🔬 Core Characteristics
- Functional: Immutable data, first‑class functions, no implicit `this` or `self`.
- Concurrency (Actor model): Lightweight processes (not OS threads) communicate via message passing.
- Fault‑tolerant: “Let it crash” philosophy with supervisors and OTP.
- Metaprogramming: Hygienic macros (compile‑time AST transformation).
- Polyglot: Seamless interoperability with Erlang libraries.
- Tooling: Built‑in build tool (Mix), package manager (Hex), and interactive shell (IEx).
- Real‑time: Used for low‑latency web apps (Phoenix framework) and embedded systems.
📊 Industry Usage
Elixir powers high‑traffic websites (Pinterest, Discord, Bleacher Report), messaging systems, IoT platforms, and financial services. The BEAM VM can handle millions of concurrent connections with minimal resource usage. Companies like WhatsApp (Erlang) and Discord (Elixir) rely on its robustness.
📊 Basic Types
🎯 Complete Definition
Elixir types are all immutable. The basic categories include integers, floats,
booleans, atoms, strings, lists, tuples, and binaries. Types are inferred dynamically but with
strong typing (no implicit coercion). The is_* guard functions allow runtime checks.
🏷️ Type categories
- Integer: Arbitrary precision (big integers).
- Float: 64‑bit double precision;
1.0. - Boolean:
trueandfalse(actually atoms). - Atom: Constant whose value is its name (
:ok,:error). - String: UTF‑8 binary, written
"hello". - List: Linked list, e.g.
[1,2,3]. - Tuple: Fixed‑size contiguous memory, e.g.
{:ok, value}. - Binary: Sequence of bytes,
<<1,2,3>>.
🔧 Special types
Ranges (1..10), Keyword lists ([{:name, "val"}] or [name: "val"]),
Maps (%{key: value}), and Functions (fn x -> x end).
🔢 Operators
🎯 Complete Definition
Operators in Elixir are either built‑in (like arithmetic) or defined as macros
(like |>). Because everything is immutable, operators never mutate; they return new values.
Important operators include the pipe |>, concatenation <> for strings/binaries,
and the match operator = (which performs pattern matching, not assignment).
📋 Operator Categories
- Arithmetic:
+,-,*,/(returns float),div/2,rem/2. - Comparison:
==,!=,===(strict),!==,<,>,<=,>=. - Logical:
and,or,not(strict, require boolean).&&,||,!(allow any type). - Binary:
&&&(AND),|||(OR),^^^(XOR),<<<,>>>. - Pipe:
|>passes left result as first argument to right function. - String:
<>concatenation. - In:
inchecks membership (1 in [1,2,3]).
🔀 Pattern Matching
🎯 Complete Definition
Pattern matching is the cornerstone of Elixir. The = operator is
the match operator, which attempts to match the right‑hand side against the left‑hand pattern.
If successful, variables on the left are bound. Matching can destructure tuples, lists, maps, and
structs. It is used extensively in function clauses, case, and with.
🔍 Matching contexts
- Variable binding:
x = 1bindsxto 1. - Tuple destructuring:
{:ok, data} = {:ok, 42}bindsdata. - List matching:
[head | tail] = [1,2,3]giveshead=1, tail=[2,3]. - Map matching:
%{key: value} = %{key: 10}bindsvalue=10. - Pin operator
^: Use existing variable's value in pattern.
🔄 Control Flow
🎯 Complete Definition
Control flow in Elixir relies on pattern matching and recursion rather than
traditional loops. Constructs include case, cond, if/unless,
and with (for chaining happy paths). All branches must return compatible types;
there is no early return except inside functions.
🏗️ Control Structures
- case – pattern match against multiple clauses.
- cond – series of conditions (like else‑if).
- if / unless – also available as inline
if condition, do: .... - with – combines pattern‑matching steps; fails fast if any mismatch.
⚙️ Functions
🎯 Complete Definition
Functions are first‑class citizens. Named functions are defined inside modules
with def / defp (private). Anonymous functions use fn ... end.
Elixir supports guard clauses, default arguments, and multiple clauses via pattern matching.
Functions are identified by name and arity (count/1).
🏗️ Function Features
- Named functions:
def add(a, b), do: a + b - Multiple clauses:
def fact(0), do: 1; def fact(n), do: n * fact(n-1) - Guard clauses:
def max(a, b) when a >= b, do: a - Default values:
def greet(name \\ "World") - Anonymous:
sum = fn (x,y) -> x + y end - Capture:
&(&1 + &2)shorthand.
📋 Collections
🎯 Complete Definition
Collections include lists (linked), tuples (ordered, fixed‑size), maps (key‑value), and keyword lists (proplists). All are immutable. Operations return new collections. Lists are efficient for prepend/head‑tail recursion; tuples for small fixed data; maps for associative arrays.
🏗️ Collection Details
- List:
[1,2,3]– head/tail access, concatenation++, difference--. - Tuple:
{:ok, value}– indexed access viaelem(t, index),put_elem. - Map:
%{a: 1, b: 2}or%{"key" => value}– fast key lookup, update with%{map | key: new}. - Keyword list:
[name: "Elixir"]– list of tuples, allows duplicate keys, often used for options.
🔑 Enum & Stream
🎯 Complete Definition
Enum module provides eager, polymorphic functions for working with collections (anything enumerable). Stream provides lazy, composable enumerables that avoid intermediate lists and can work with infinite collections. Both follow the functional pipeline style.
🔥 Common functions
map/2,filter/2,reduce/3,each/2sort/1,uniq/1,join/2any?,all?,member?chunk_every/2,zip/2- Stream functions:
Stream.map/2,Stream.filter/2,Stream.cycle/1
📝 Strings & Binaries
🎯 Complete Definition
Strings are UTF‑8 encoded binaries (binary type). They are immutable
and support interpolation "#{var}". Character lists (single‑quoted) exist for Erlang
compatibility but are rarely used. Binaries (<< … >>) represent raw bytes. The
String module provides Unicode‑aware functions.
🔧 Key operations
length/1(byte count) vsString.length/1(graphemes).split/2,join/2,trim/1upcase/1,downcase/1,capitalize/1contains?,starts_with?to_integer/1,to_atom/1
📦 Modules & Structs
🎯 Complete Definition
Modules are namespaces for functions, macros, and structs. They can be nested,
and attributes (@name) store module‑level constants. Structs are
extensions of maps with a fixed set of keys, defined inside modules via defstruct.
They provide compile‑time checks and default values.
🏗️ Module Features
defmoduledefines a module.@moduledocdocumentation.defstructdefines a struct.@typeand@specfor typespecs.use/import/alias/requirefor compilation directives.
🛡️ Protocols
🎯 Complete Definition
Protocols are a way to achieve polymorphism in Elixir: a protocol defines a
set of functions that can be implemented for different data types. They are similar to interfaces
in OOP but are open (can be implemented for any type, even built‑ins). Common built‑in protocols:
Enumerable, Inspect, String.Chars.
🔌 Defining & using
defprotocol declares the functions; defimpl provides implementations
for specific types. Protocols can also be derived automatically for structs.
⚠️ Exceptions
🎯 Complete Definition
Exceptions in Elixir are raised with raise/1 and rescued with
try/rescue. Elixir follows Erlang’s “let it crash” philosophy; exceptions are often
used for programmer errors, while expected failures are handled via tuples ({:ok, _}
or {:error, _}). The try block can also have catch and
after.
🛠️ Exception constructs
raise "oops"– raises RuntimeError.raise ArgumentError, message: "bad arg"try do ... rescue e in RuntimeError -> ... endafter– always runs.throw/catch– non‑local return (less common).
⚡ Concurrency (Actor)
🎯 Complete Definition
Concurrency in Elixir uses the actor model: lightweight processes (not OS threads)
that isolate state and communicate via asynchronous messages. Processes are spawned with spawn,
and messages are sent with send and received with receive. Thousands of
processes can run simultaneously. The BEAM VM preemptively schedules them.
🏗️ Process primitives
spawn(fn -> ... end)– creates a new process, returns PID.send(pid, message)– sends async message.receive do ... end– receives a message (blocks).Process.register(pid, name)– alias by atom.self()– current process PID.
🏗️ OTP & Supervisors
🎯 Complete Definition
OTP (Open Telecom Platform) is a set of libraries and design principles for
building robust, fault‑tolerant applications. Key behaviours: GenServer (generic server),
Supervisor (process monitoring), Application (component packaging).
Supervisors define restart strategies (one‑for‑one, rest‑for‑one) to keep systems alive.
🏭 Core OTP behaviours
use GenServer– implements server with call/cast.use Supervisor– supervises child processes.Application– start/stop callbacks.Task– asynchronous units of work.Agent– simple state containers.