Elixir charlists: wat
In Elixir, a range is a sequence
of integers with a fixed step. The most common method of declaring a range is
to use the x..y
syntax. Enum
is a collection of algorithms to work on
enumerables. Enum.to_list
converts an enumerable to a list.
Armed with that knowledge, review the following code and try to consider what the results should be.
Enum.to_list -1..10
[-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Hover to show
Enum.to_list 23..59
[23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59]
Hover to show
Enum.to_list 32..78
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMN'
Hover to show
Enum.to_list 79..129
[79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, ...]
Hover to show
Unless you already know where I'm going with this I bet you were surprised by
the output of Enum.to_list 32..78
. Why did the REPL spit back a bunch of
characters when we defined a list of integers?
This happens because Elixir parses the resulting list as a charlist, a string-like remnant from Erlang:
A charlist is a list of integers where all the integers are valid code points.
Note that the above definition talks about ASCII code points, not Unicode. The first ASCII code point is 32 (' ') and the last ASCII code point is 126 ('~').
This is surprising behavior. I can see a situation where you debug a system,
stepping through the stack, printing some suspicious variables. Suddenly you
spot something that looks like a type error. The variable foo
which should be
a list of integers, looks like it's a string? But in fact, it's just a list of
integers that all happen to be in the [32,126] range.
> Enum.to_list 32..126
' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'
> Enum.to_list 32..127
[32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, ...]
> Enum.to_list 31..126
[31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, ...]
I imagine that, like Python's default dynamic parameters, this is just something that experienced Elixir programmers learn to distinguish. The single quotes are a tell-tale that the result is not a normal string, but a charlist. I guess it is also pretty easy to remember, given the very Wat-like experience when you see this occur for the first time.