When Spaces Matter in Elixir

Everett Griffiths
3 min readOct 3, 2021

I have a confession… when I first heard about how Python forgoes the “confusing” soup of characters in favor of blank spaces to denote its blocks, I balked. In fact, I hated it. I became King Richard III and yelled “a semi-colon! a curly brace! My kingdom for a horse that sits on grapefruit!” Or something.

As if it weren’t bad enough that we have to pick smart-quotes out of anything copied and pasted from the internet like raisins out of cookies, with Python we have to be the space police too. Boo.

Spaces: the final frontier in keeping your code from compiling

On the other end of the universe was PHP, where pretty much all space could be collapsed and the code could still run. It’s always fun when you discover a malicious payload on a web server that has been fuzzed and compressed into a single dense lump of incomprehensible code with no spaces, but somehow still manages to install a backdoor into your server. Also boo.

You might be surprised that there is a spectrum here. In fact, not many people realize that in Elixir, spaces are SOMETIMES significant. So prepare to be wowed, space-fans with this listicle that details those Elixir gotchas where spaces (or lack thereof) might bite you in the semi-colon.

Maps. %{not:"Good"} vs %{all: "Good"} — your colon must be followed by a …(wait for it)… SPACE. Thankfully, the errors have improved to help those of us who forget, so on recent versions you’ll see a helpful error like ** (SyntaxError) keyword argument must be followed by space

So just remember: Your colon needs space.

IEx. Elixir’s REPL. It’s maddening that you can’t do multi-line operations because line-breaks screw things up (at least, until Elixir v1.12.0 where this problem has been addressed). Trying to paste anything with a pipe |> like:

%{touch: "The Sky"}
|> Map.get(:touch)

and it results in an error because (of course), the spaces (i.e. line breaks) are interpreted.

iex> %{touch: "The Sky"}
%{touch: "The Sky"}
iex> |> Map.get(:touch)
** (SyntaxError) iex:3:1: syntax error before: '|>'

The secret to overcoming SPACE-MADNESS in IEx is… PARENTHESES. (Ren and Stimpy anyone?) That’s right: just wrap your input in parens and your life will be saved:

iex> (
%{touch: "The Sky"}
|> Map.get(:touch)
)
"The Sky"

String Parsing (e.g. EEx, moduledocs). This one isn’t a gotcha but rather an under-appreciated feature. To explain what this is and why this is so nice, I have to reach way back to when I was teaching underlings how to code with PHP. We worked with templates that looked something like this:

<html>
<head>
<?php include('header.php'); ?>
</head>
...
</html>

with a header.php like

<title>My Title</title>
<meta name="description" content="Madness">

And when it renders, it renders like so:

<html>
<head>
<title>My Title</title>
<meta name="description" content="Madness">
</head>
...
</html>

And yes, your eyes are not deceiving you, that text would end up flush with the left margin. My erstwhile student dutifully combed through all of his templates and added spaces so they would render with the proper indentation. Yes. The guy was that meticulous.

Had Elixir been around back then, we would never have had this problem. Why? Because when strings are parsed in Elixir such as those inside @moduledocs , EEx, or strings enclosed in triple quotes""" Elixir detects how much it is indented and it automatically adjusts the output.

“Wow, I’m glad they thought of that!”

--

--