Erlang's iolist

Look Mom, no object

I don't remember who sold me object orientation, but he was a great liar. — José Valim

In Erlang, there are no objects. It's a purist and functional language. Everything is made of primitives types; three differents kind of lists (list, tuple, binary), no decent string representation. It's one of the weird things when you discover Erlang. Weirdness and integrism are the beauty of Erlang: Erlang doesn't want to be kind with developers, and erlanguists like it. "No object" is not a motto, it's a strategy to handle communication efficiently. Everything is message, everything can go through a wire. There are no objects, but conventions: specific representation with specific functions. dict, array, digraph, gb_sets, gb_trees, lists, orddict, ordset, proplists, sets, string, unicode. All of them are in the standard library. Useful to manipulate, efficient in production, ugly to display. No syntax sugar or cute display, everything is a naked primitive object.


Now, you have unplugged "object pattern" from your brain. Plug in "list manipulation" and "pattern matching": Erlang is a functional language.

And IOList is one of Erlang's secret weapon. Although almost undocumented, you can find references to it in the documentation or while debugging. So, what is it used for?

List appending is a curse. You want to concatenate two lists? Build a new one with enough room. Copy each items from the first list, then each items from the second one. But when you concatenate inside a loop, the amount of copies becomes huge, and first items are copied again and again.

Not so efficient…

Erlang has a tactic to handle concatenation. When you want to concatenate two things, just put them in a new list - a new one for each concatenation. The result is no more a flat list, Erlang names it a deep list. And when your bag is full, you can flatten it with lists:flatten. You append many times, and flatten one time.

1> A = "Hello".
2> B = " world".
" world"
3> C = [A, B].
["Hello"," world"]
4> lists:flatten(C).
"Hello world"

However, APIs done right (io:format, file:write, gen_tcp:write…) accept iolist, so flattening is not mandatory.

Some functions return iolists, dont' be surprised:

1> Dump = io_lib:format("dump ~p~n", [{foo, "Hello words"}]).
[100,117,109,112,32,[123,["foo",44,"\"Hello words\""],125], "\n"]
2> lists:flatten(Dump).
"dump {foo,\"Hello words\"}\n"
3> io:format(Dump).
dump {foo,"Hello words"}

In this example, an Erlang structure is dumped. When displaying hierarchical data, a deeplist (i.e. IOList) is returned. The five first numbers are ASCII value of "dump ". That's clear, it's raw data for robots, not for humans. It's more readable through lists:flatten, but use it raw in your code. When flattened, the shell interprets it as a string. Then, io:format accepts the rough iolist.

Erlang loves bags of numbers: everything is just compound of 8 bits brick, isnt'it?

blog comments powered by Disqus