Why is the word do used to start blocks?

There is a confusion between imperative, functional and sequential. The do construct does not imply imperative programming, not even in Haskell. It implies sequence. It means that, any effect inside a monadic construct, even if delayed, will happen in order. It is easy to see how this is important for IO because you want to write to an IO device in a given order and not have the compiler shuffle that.

Imperative programming is about your program state and commands. Take C for example, where traversing an array typically requires setting up a for loop with an index, tightly coupled to its in memory representation. Imperative programming is often associated to mutation and side-effects. You need to tell the computer where to store that value or to change its state.

That’s a contrast to functional languages where you rely on higher order functions for traversals (such as Enum.map). Or where you use recursion to emulate state, such as in Elixir processes.

However, even being mostly a functional programming language, Elixir is sequential and the do reflects that. The code inside a function is going to be executed eagerly and in the order that you have written it. Your instructions are not going to be shuffled around by the compiler.

Of course things are a bit more complex than this. The truth is that every Elixir process is sequential but altogether your system is concurrent, event-driven and possibly distributed. Elixir still has imperative bits, for example, calling defmodule Foo do ... end has a side-effect of defining a module. We can still use ets to emulate global state, etc. But I think it is important to highlight that, most of all, Elixir is functional and that each process executes code sequentially.

15 Likes