Attempt to Learn Elixir: Thinking in Elixir
Welcome to another blog post of the series Attempt to Learn Elixir. If you are reading this then I assume you have already gone through the resources shared in my previous post of this series. It is highly recommended that you at least go through the absolute basics first. In this post, we will attempt to learn about the culture of solving problems functionally and how Elixir solves it.
Elixir & OTP
Elixir is a functional programming language. Functional languages are built with functions as first-class citizens and tend to involve a declarative style of programming, where we specify what is to be done rather than focusing on how to do it. Functions are meant to be small and simple, and bigger functions are made by composing the smaller functions together.
Elixir was built on top of a mighty language called Erlang which was originally designed and developed by Erricson in the mid-'80s with the aim of building their telephony software. Elixir is a dynamically-typed language, which means data types are determined in runtime rather than compile time. Elixir code is compiled into bytecode that runs on a virtual machine. The virtual machine is called the BEAM (Bogdan's Erlang Abstract Machine) which is at the core of Erlang Open Telecom Platform (OTP). OTP is a set of Erlang libraries and design principles providing middleware to develop massively scalable soft real-time systems with requirements on high availability. Elixir can interact with Erlang code and can call Erlang libraries if the equivalent functionality doesn't exist in an Elixir library.
Elixir is the perfect blend of the power and robustness of Erlang and developer happiness and productivity of Ruby.
In functional programming, data and function are strictly separated. We should divide our problem domain into smaller modules. Each module will group related functions and they are passed data as parameters and return data to the caller. One of the key concepts of functional programming is
Immutable Data, we take the data, and pass it through a series of functions and return the result without mutating the actual data. Functions are simply data transformers. Our entire system should be made of modules that are comprised of such functions. Each module has data representation (optionally), they are called structs.
Let's say we have to return the number of lines, words, and characters of a file, then our approach would be, first to get the raw data of the file, then separate the lines, then for each line, compute the result. The data needs to be passed through all those stages and transformation, in other words:
This looks cumbersome, but Elixir has a culture of having data as the first argument of functions, that way, we can have the pipe function, which would make it:
file |> read() |> split_lines() |> calculate_stats() |> format_results()
So, it is advisable to set up our functions in such a way that data is on the first argument, the same goes with module functions that take advantage of that module's struct.
We should learn to understand
reduce really really well. They can often save us from recursions. And let us work in a beautiful flow.
Patterns are amazing, think of it more like the matching games we used to play as kids, key to enjoying Elixir is understanding and embracing
Modular design where data is transformed through functions, and pipes, and patterns emerge are the key to Thinking in Elixir. To be able to think in Elixir we first need to learn to think like functional programmers. For this, we have to grasp the concept of functional programming. Below is a good article on this.
Functional programming is not only about following some rules. It is a different way of thinking about a problem or approaching a problem. It is a declarative approach where we define what needs to be done rather than how to do it. The declarative functional mindset is something we have to master before we can write meaningful functional programs. Without the proper understanding of the functional paradigm, it is very easy to abuse any functional language. That can result in inefficient code. That's why learning to write idiomatic Elixir code is the key to developing robust and performant programs which is the actual purpose of Elixir.
Here is a talk by Dave Thomas on Thinking in Elixir.
Some key concepts of functional programming are:
- Data and functions are separated
- Functions are first-class citizens
- Functions are simply data transformers
- Functions are small and composable
- Data is immutable
- Higher-order functions
Watch this other talk by Dave Thomas for a better understanding.
We have come to the conclusion of this post. After getting the very basics of the Elixir language it is imperative that we spend some time with functional programming and try to conceptualize as much as we can before moving forward with intermediate Elixir. In this post, I have tried to give a brief idea about it. But there are a lot of things to learn. Try to explore by yourself and learn about each topic mentioned in this post. Follow the official documentation , Elixir School and Programming Elixir book if possible. After you are comfortable with the basic concepts of functional programming and Elixir you are ready to dig deeper into the Elixir ecosystem.