Why is the word do used to start blocks?

Just wondering what the thought behind using the word do to start blocks is.

On the face of it, it seems like a strange word to use in a functional language. Sounds very imperative.

1 Like

I do think that’s mainly because the syntax is heavily inspired by ruby.

But one could even think that a block in elixir is very close to the identity monad. And do is used by Haskell to add sugar around monads. But since everything is in identity, there is nothing special and we omit the fact and mostly ignore it.

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

Wow. That is a much more satisfying and informative answer than I was expecting, thanks Jose. :clap:

1 Like