I just noticed this in Iex:
iex(1)> [1,2,3,4,5,6,7,8,9,10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iex(2)> [7,8,9]
'\a\b\t'
iex(3)> [7]
'\a'
iex(4)> [6]
[6]
iex(5)> [6,7]
[6, 7]
iex(6)> [7,8]
'\a\b'
Why is this happening?
I just noticed this in Iex:
iex(1)> [1,2,3,4,5,6,7,8,9,10]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
iex(2)> [7,8,9]
'\a\b\t'
iex(3)> [7]
'\a'
iex(4)> [6]
[6]
iex(5)> [6,7]
[6, 7]
iex(6)> [7,8]
'\a\b'
Why is this happening?
Hello and welcome,
it’s because they are the same thing…
a charlist is a list of char.
iex> [97, 98, 99]
'abc'
iex> [97, 98, 99, 0]
[97, 98, 99, 0]
iex> [97, 98, 99] == 'abc'
true
iex> Enum.map 'abc', & IO.inspect(&1)
97
98
99
'abc'
If it can, it will output char
For information how to change this behaviour, see this previous answer: IEX - char printing - odd behavior
As other said, in addition You can use i/1
helper function in IEx session to get more informations about given type:
iex(1)> i [7,8,9]
Term
'\a\b\t'
Data type
List
Description
This is a list of integers that is printed as a sequence of characters
delimited by single quotes because all the integers in it represent printable
ASCII characters. Conventionally, a list of Unicode code points is known as a
charlist and a list of ASCII characters is a subset of it.
Raw representation
[7, 8, 9]
Reference modules
List
Implemented protocols
Collectable, Enumerable, IEx.Info, Inspect, List.Chars, String.Chars
Elixir seems to be treating these as Charlists (scroll down a little in that)
I don’t know why it’s happening, but if I had to guess by looking at the ascii table, it’s because 0-6 are (I think) non-printable characters
Starting with 7, we have characters that are “printable” via escape codes. The most noticeable mappings you might recognize:
[9]
maps to \t
, which is a “tab” in ASCII[10]
maps to \n
which is a new line[13]
maps to \r
which is a carriage returnWhy Elixir does this is unclear to me but it’s an interesting observation
Edit: A little more info
The description in the i
helper function by @hauleth plus the explanation/link by @Nicd, coupled with the docs on info make sense to me now (it does a check to see if a character is printable or not). Leaving the info above in case it was useful
Because that’s the way Erlang represents strings. It makes interaction a lot easier when errors from Erlang are prettyprinted as charlists by default rather than as a list of strings.
It’s not really treating them differently, because they are charlists. As charlists are just lists of integers that represent characters, there is no way to differentiate them from “normal” lists. IEx is the one treating them differently when outputting them, as it tries to be friendly to you.
There is a similar thing with binaries, where strings are just binaries that contain UTF-8 data. IEx will print those binaries as strings. If there is data that is not valid UTF-8 or is not printable, it will print the bytes as numbers.
IEx is the one treating them differently when outputting them, as it tries to be friendly to you.
Thank you for this follow up. I didn’t read your previous link before I posted my response, but that made it much more clear. I’m going to use your suggestion in your other post (not to pretty print these) to configure my IEx
There is a similar thing with binaries, where strings are just binaries that contain UTF-8 data
You know it’s really interesting that people freak out over [10] being ‘\n’ but few people would freak out over <<10>> being silently represented as “\n”. I wonder why.
Because the latter case is rarely seen.
Most play with lists in iex, not binaries.
And if they do, then they are probably already beyond that point.
Most languages have separate string and list datatypes and most of them don’t distinguish between single and double quotes, as both represent the same kind of string. Therefore it’s strange that a list might suddently become a “string”. <<10>> = "\n"
on the other hand are both “strings” therefore the same datatype; no sudden “switch” of type.
This confusion is why I’m still hoping we can make this a reality some day: Replace 'charlist' by ~c[charlist] in your own codebases