While an Erlang string is a list of integers, an "iolist" is a list whose elements are either integers, binaries or other iolists, e.g.
["foo", $b, $a, $r, <<"baz">>]. That iolist represents the string
While you can convert an iolist to a binary with
iolist_to_binary/1, you often don't need to, since Erlang library functions such as
gen_tcp:send/2 accept iolists as well as strings and binaries.
What is an iolist?
It's any binary. Or any list containing integers between 0 and 255. Or any arbitrarily nested list containing either of those two things.
Use deeply nested lists of integers and binaries to represent IO data to avoid copying when concatenating strings or binaries.
They are efficient even when combining large amounts of data. For example combining two fifty kilobyte binaries using binary syntax
<<B1/binary, B2/binary>> would typically require reallocating both into a new 100kb binary. Using IO lists
[B1, B2] only allocates the list, in this case three words. A list uses one word and another word per element, see here for more information.
++ operator would have created a whole new list, instead of just a new two element list. Recreating lists to add elements to the end can become expensive when the list is long.
In cases where the binary data is small, allocating IO lists can be greater than appending the binaries. If the binary data can either be small or large it is often better to accept the consistent cost of IO lists.
Note that appending binaries is optimised as described here. In short, a binary can have extra, hidden space allocated. This will be filled if another binary is appended to it that fits in the free space. This means that not every binary append will cause a full copy of both binaries.