Elixir’s combination of modern language features, and a 30-year-old battle-tested foundation at its core, has made it increasingly popular over the past year.
This course provides a strong foundation for writing general-purpose functional code, and is intended for developers already proficient in another language.
1 — Liftoff
Elixir is in a fairly unique position as a programming language, in that it combines contemporary language features and excellent developer ergonomics with the established and battle-tested Erlang ecosystem.Agenda
Origins, Foundations & Core Principles
When setting off to learn a new programming language, it’s often incredibly useful to understand the language’s foundations. In this case, we’re dealing with a language built on top of another language, which runs on a virtual machine that supports other languages
Elixir’s interactive shell (IEx) is one of the most powerful tools in your toolbox. We’ll outline some of the most useful features for beginners, including:
- Running scripts
- Getting metadata about a value
- Accessing embedded documentation
- Inspecting the state of a particular process
IO & Files
As with most programming languages, it’s useful to know how to interact with files and humans. We’ll take care of this early on, and notice a few things that foreshadow some interesting aspects of Elixir’s concurrency model.
EXERCISE: Reading a CSV File
We’re going to have to take a few things for granted, since we’re just starting out, but let’s use some existing well-documented code to read a CSV file into memory, and print some information about it to the console.
2 — Types, Operators & Control Flow
Our journey starts with basic types and procedural logic. Even if you’re experienced in a wide range of programming languages, there’s going to be a lot of stuff – even at this basic level – that may change the way you look at writing code forever.Agenda
Math & Strings
There’s no getting away from these kinds of things. Eventually you’re going to need to work with numbers and text, so we’ll start with a crash course in some core APIs (including a dip in the Erlang pool) that will make life easy.
There’s a lot of capability here, but we’ll stay close to the commonly-useful and pragmatic path.
EXERCISE: Projectile Motion
We’ll create a simple program that calculates an object’s projectile motion, given a launch angle and initial velocity.
EXERCISE: String Acrobatics
We’ve got a bunch of functions that do various things to string values, but our tests are failing. Let’s fix that!
Break for Lunch
It stands to reason that functions are really important in a functional programming language. We’ll build and work with named and anonymous functions, combine functions together to form pipelines, and even map out some higher-order functions of our own.
Tuples & Lists
Often times we find ourselves needing to work with several objects in a “collection”, and will need to choose between Elixir’s List and Tuple types. We’ll compare and contrast tuples and lists, and write a few programs highlighting the benefits of each.
EXERCISE: Fibonacci Pyramid
Using our knowledge of functions and recursion in Elixir, let’s build a function that writes a Fibonacci pyramid to the console.
20 levels deep!
Associative Data Structures
We have two main associative data structures in Elixir: keyword lists and maps. Let’s learn more about them!
EXERCISE: Building up a List
Assembling a bunch of items in a list is really fast, as long as we do it in a way that doesn’t involve moving existing items around in memory. We’ll write two programs, one which assembles a bunch of dictionary words into a tuple, and another that uses a list instead.
Pattern Matching & Guards
This modern language feature allows destructed assignment, and is often used to define several variants of a function, each to handle a specific scenario. This application of pattern matching reduces what would otherwise be a lot of internal function complexity by huge amounts.
EXERCISE: Function Refactoring
We’ve got an Elixir module that involves some code that could benefit from some pattern matching magic. Refactor the monolith function so all use of if/else are replaced by creating new functions oriented toward handling that specific pattern of arguments.
EXERCISE: A world without if/else
You’ll be given an Elixir module that’s currently a little messy and confusing. Untangle it by replacing all of the if/else logic with
case.statements and by applying pattern matching in function clauses.
Remember: your goal is to make your code as easy to read and maintain as possible: be clever, but not confusing.
Recap & Wrap Up
We’ll go over everything we’ve covered today, and connect them back to the big picture. This is a great time for Q&A that’s broader than the specific topics we’ve covered so far.
3 — Writing Modular Programs
Elixir’s module system allows us to define layers of related functions. In this part of the course, we’ll explore the concepts of modules, and the ability to reference code in one module from another.Agenda
We’ll recap the ground we covered in day 1 of this training, so it’s fresh in your mind, as we continue building up toward Elixir proficiency!
Modules & Three Important Directives
Modules are just a group of several functions, some of which may be private and some of which may be public. Modules give us the ability to define named functions using the
def macro, which offer a few other features that were unavailable in the world of anonymous functions.
EXERCISE: Mission Control
We’ve got a set of tests for a couple of Elixir modules that are used to control a space ship. Alter the code to make the unit tests pass, and ensure that you’ve kept as much of each module’s internal functionality private as possible.
use macro is not strictly a directive, it’s of particular importance when considering “mixins” for common functionality, shared across multiple concrete modules.
EXERCISE: Extending a Module
use macro can essentially be used to decorate a module with some code from another module.
Protocols & Behaviors
Protocols are a mechanism for polymorphism in Elixir, where an implementation of a certain contract is defined on a per-type basis. In other languages, this contract would be called an interface (Java), or a pure abstract class (C++)
Under the hood, part of how this works is by way of a Behavior: a definition of a set of functions that modules who adopt this behavior must implement.
EXERCISE: Serializer Protocol
Given a list of values, we want to be able to generate a string representation, either in CSV or JSON array format. Design a protocol, and adopt that behavior in each of two modules:
Break for Lunch
4 — Working With Data Structures
Earlier we outlined and worked with several different types of data structures. Let’s take a closer look at some of these methods.Agenda
Enum & Map
We’ve learned about how to create and work with list and map literals in very basic ways. Let’s take a look into some of the tooling that Elixir provides as core language features, for working with these data structures.
EXERCISE: Map, Filter, Reduce
We have a program that starts with a list of objects read from a file. Using the built-in functions available in the
Map modules, filter out “inactive” items (objects where the “active” attribute is not
true), and then log a list of object names to the console.
Taming List Enumeration with Comprehensions
Often we find ourselves looping over something enumerable; mapping values into another list; and potentially filtering out some unwanted items. Comprehensions use a generator and a filter to provide some excellent syntactic sugar for this kind of task.
Take another pass at the previous exercise, and use a comprehension to devise a concise solution.
Lazy Operations with Streams
Stream module offers some of the same capabilities that we enjoy in the
Enum module, but when working with Streams, computations are performed lazily. This is particularly useful for dealing with huge (or infinitely huge) collections.
EXERCISE: Skimming a good book
Given the entire text of the book ~Gulliver’s Travels~, find the highest- Scrabble-scoring word within the first 1000 lines.
Recap & Wrap Up
We’ll round out the course by recapping everything we’ve learned, and finish with some tips for next steps in your mission to become an ace Elixir developer!