2. Characteristics of Functional Programming
• Avoids mutable data & changing state
• Higher-order functions
• Declarative style of code
• Functional programming method focuses on results, not the process
• It does not support iteration like loop statements and conditional statements
like If-Else
3. Why should I learn FP?
• Easier handling of Concurrent programs
• Clearer Testing & Debugging
• Better maintainability
• Easier to understand
• Offers better modularity with a shorter code
• Hot code deployment and fault tolerance
4. Functional Programing vs OOP
• Definition: Based on Functions ~ Objects
• Data: Uses immutable data ~ mutable data
• Programming Model: Declerative ~ Imperative
• Support: Supports Parallel Programming ~ Not Support Parallel Programming
• Execution: can be in any order ~ should be in particular order
• Iteration: Recursion ~ Loops
• Basic Elements: Variables & Functions ~ Objects & Methods
5. What is Elixir
• Elixir is a dynamic, functional language for building scalable and
maintainable applications.
• Elixir leverages the Erlang VM(BEAM), known for running low-latency,
distributed and fault-tolerant systems.
• Created by José Valim circa 2012. Former Rails Core Team member.
• Compiles to Erlang bytecode.
• Can call to any Erlang library with no performans penalty.
6. Elixir Features
• Enables developers’ productivity by offering amazing tooling and beautiful
documentation.
• The Elixir programming language wraps functional programming with immutable
state and an actor-based approach to concurrency in a tidy, modern syntax.
• In particular, immutable data structures help concurrency quite a lot, and
pattern matching is great for writing declarative code.
• Elixir has dynamic typing. Types are checked in run-time, not during compilation.
• We can do concurrency programming without having to use abstractions such as
locks or semaphores.
7. Concurrency
• Elixir uses lightweight threads of execution (called processes).
• These are isolated, run across all CPUs, and communicate through
messages.
• Together with the immutability of data that comes from the functional nature
of the language, this makes it less hard to write concurrent programs in Elixir.
8. Scalability
• These same processes allow us to scale systems easily
• Horizontally (adding more machines to the cluster)
• Vertically (using the available resources of the machine more efficiently).
9. Fault Tolerance
• Elixir and Erlang have a unique approach to fault-tolerance.
• While things sometimes inevitably fail in production, lightweight processes can
be quickly restarted by the supervisor system.
11. Data Structures
• Tuples: Elements contiguously in memory.
• {:reply, 123}
• Linked List: like arrays & values can be any type.
• [1, 2, 3] ++ [4, 5, 6]
• Binaries: Strings are UTF-8 encoded binaries.
• <<104, 101, 108, 108, 111>> (hello)
• Maps
• %{ key => value, key => value }
• Charlist: list of integers where all the integers are valid code points
• ‘hello' ++ ‘ world'
12. Functions
• Anonymous functions
• Can be passed as argument
• add = fun (a,b) -> a + b end
add.(3,4)
• Named functions
• Just defined in module
• Can be called without “.”
13. Pattern Matching
• a = 1 meaning is no assigning, is binding variable. Left hand side is equal to
right hand side.
• Elixir allows rebinding a variable
• a = 1
a = 2
• [ a, b, _ ] = [ 1, 2, 3 ]
• Pin operator(“^”), a variable’s existing value rather than rebinding the variable
• [ ^a , 2 , 3 ] = [1 , 2 , 3 ]
14. Guards
• A way to augment pattern matching with more complex checks.
• Guards start with the when keyword.
• Where used:
• function clauses
def foo(term) when is_integer(term), do: term
def foo(term) when is_float(term), do: round(term)
15. Guards
• case expressions
case x do
1 -> :one
2 -> :two
n when is_integer(n) and n > 2 -> :larger_than_two
end
• anonymous functions
larger_than_two? = fn
n when is_integer(n) and n > 2 -> true
n when is_integer(n) -> false
end
16. Pipe Operator
• It takes the output from the expression on its left side and passes it as the first
argument to the function call on its right side.
iex> Enum.map(List.flatten([1, [2], 3]), fn x -> x * 2 end)
translates to
iex> [1, [2], 3] |> List.flatten() |> Enum.map(fn x -> x * 2 end)
[2, 4, 6]
17. Enum
• Enum module provides a huge range of functions to transform, sort, group,
filter and retrieve items from enumerables.
• All the functions in the Enum module are eager.
• Enum module can work with any data type that implements the Enumerable
protocol.
iex> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
iex> Enum.reduce(1..3, 0, &+/2)
6
18. Stream
• As an alternative to Enum.
• Supports lazy operations.
• Instead of generating intermediate lists, streams build a series of
computations.
• useful when working with large, possibly infinite collections.
iex> odd? = &(rem(&1, 2) != 0)
iex> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?)
#Stream<[enum: 1..100000, funs: […]]>
19. Processes
• In Elixir, all code runs inside processes.
• Processes are isolated from each other run concurrent to one another.
• Communicate via message passing.
• Processes are not only the basis for concurrency in Elixir, but they also
provide the means for building distributed and fault-tolerant programs.
• Processes in Elixir are extremely lightweight in terms of memory and CPU.
• May be tens or even hundreds of thousands of processes running
simultaneously.
20. Process - Spawn
• The basic mechanism for spawning new processes.
• Returns a PID(process identifier).
• The spawned process will execute the given function and exit after the
function is done.
iex> pid = spawn fn -> 1 + 2 end
#PID<0.44.0>
iex> Process.alive?(pid)
false
21. Process - send & receive message
• When a message is sent to a process, the message is stored in the process
mailbox.
• If there is no message in the mailbox matching any of the patterns, the current
process will wait until a matching message arrives.
iex> send self(), {:hello, "world"}
{:hello, "world"}
iex> receive do
…> {:hello, msg} -> msg
...> {:world, _msg} -> "won't match"
...> end
"world"
22. Process - Links
• When a process dies parent process doesn’t die, because processes are
isolated.
• If we want the failure in one process to propagate to another one, we should
link them.
• Tasks build on top of the spawn functions to provide better error reports and
introspection.
iex(1)> Task.start fn -> raise “oops"end
{:ok, #PID<0.55.0>}
23. Module Attributes
• They serve to annotate the module, often with information to be used by the
user or the VM.
• @moduledoc, @doc, @behaviour, @before_compile
• They work as constants that read at compilation time and not at runtime
• They work as a temporary module storage to be used during compilation.
24. Structs
• Structs are extensions built on top of maps that provide compile-time checks
and default values.
• Structs take the name of the module they’re defined in.
25. Protocols
• A mechanism to achieve polymorphism in Elixir.
• Protocols allow us to extend the original behavior for as many data types as
we need.
26. Comprehensions
• Comprehensions groups common to loop over an Enumerable, often
filtering out some results and mapping values into another list tasks in to for
special form.
• A comprehension is made of three parts: generators, filters, and
collectables.
• Generators support pattern matching to filter.
• The result of a comprehension can be inserted into different data structures by
passing the :into option.
27. try, catch, and rescue
• Elixir has three error mechanisms: errors, throws, and exits.
• Errors (or exceptions) are used when exceptional things happen.
• Errors can be rescued using the try/rescue construct.
• Elixir developers rarely use try/rescue construct.
• Instead of rescuing an error, we’d rather “fail fast” since the supervision tree
will guarantee.
28. try, catch, and rescue
• Throws, a value can be thrown and later be caught.
• It is not possible to retrieve a value unless by using throw and catch.
• Exit, when a process dies, it sends an exit signal listened by supervisor.
• After, it’s necessary to ensure that a resource is cleaned up after some action
that could potentially raise an error.
29. Typespecs
• Elixir is a dynamically typed language, so all types in Elixir are checked at
runtime.
• Elixir comes with typespecs, which are a notation used for:
• @spec, declaring typed function signatures -> document function
signatures.
• @type, declaring custom types -> increase its readability.
30. Behaviours
• Define a set of functions that have to be implemented by a module.
• Ensure that a module implements all the functions in that set.
• Must implement all the functions defined with the @callback attribute.
31. Mix
• Mix is a build tool that ships with Elixir that provides tasks for creating,
compiling, testing your application, managing its dependencies and much
more.
• To create first project:
• $ mix new kv --module KV
• To start iex session inside the project:
• $ iex -S mix
• To run tests
• $ mix test
32. OTP
• OTP (Open Telecom Platform) is a set of libraries that ships with Erlang. But
it isn’t used just for telecom nowadays.
• OTP defined as three components: Erlang itself, set of libraries, set of
system design principles.
• It certainly solves many problems that includes application discovery, failure
detection and management, hot code swapping, and server structure.
33. Agent
• Simple wrappers around state.
• If all you want from a process is to keep state, agents are a great fit.
• Everything that is inside the function we passed to the agent happens in the
agent process.
34. GenServer
• A behaviour module for implementing the server of a client-server relation.
• GenServer(Generic Server) is a process and it can be used to keep state,
execute code asynchronously and so on.
• The advantage of using a GenServer, it will have a standard set of interface
functions and include functionality for tracing and error reporting. It will also
fit into a supervision tree.
• There are two types of requests you can send to a GenServer
• call: synchronous and the server must send a response back.
• cast: asynchronous, the server won’t send a response back and therefore
the client won’t wait for one.
35. Supervisor
• A supervisor is a process which supervises other processes, which we refer to
as child processes.
• Used to build a hierarchical process structure called a supervision tree.
• Supervision trees provide fault-tolerance and encapsulate how our
applications start and shutdown.
• The act of supervising a process includes three distinct responsibilities
• start child processes.
• restart a child process, either because it terminated abnormally
• shutting down the child processes when the system is shutting down.
36. ETS
• ETS(Erlang Term Storage) is a cache mechanism.
• ETS allows us to store any Elixir term in an in-memory table.
• Access controls:
• public — Read/Write available to all processes.
• protected — Read available to all processes. Only writable by owner
process. This is the default.
• private — Read/Write limited to owner process.