Weird Output when doing list concatenation and subtraction

I am a Elixir noob. I tried writing this program:

# (Linked) Lists
l1 = [23, 13, 6, 3, 87, 2, 1]
l2 = [2, 6]
IO.puts "l1: #{l1}; l2: #{l2}"
IO.puts "Concat: #{l1 ++ l2}"
IO.puts "Subtract: #{l1 -- l2}"
IO.puts "Head hd(l1): #{hd(l1)}"
IO.puts "Tail tl(l1): #{tl(l1)}"
IO.puts "====================================================================="

But the output I got was:

W; l2: 
Woncat: 
Wubtract: 
Head hd(l1): 23
Wail tl(l1): 
=====================================================================

I am certain I am missing an info on something, I am just not sure what it is. Can someone tell me what I am doing wrong?

String.Chars for lists is implemented to consider the lists as a list of unicode code points.

The 87 represents the W you see represents the at the beginning of the line, the 13 (Carraige return) causes that it is printed at the beginning of the line.

23, 6, 3, 2, and 1 are some other kind of control characters, usually ignored by modern terminals.

If you want to see the list you need to use inspect, within the interpolation, eg. IO.puts("l1: #{inspect(l1)}").

2 Likes

Nevermind people. I just found out what info I was missing :stuck_out_tongue:

I came across this line in documention right after I posted this:

When Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters)

So, I guess one of those numbers got interpreted as a escape sequence that deletes all the previous values :stuck_out_tongue:

I would just like to know if my assumption is right

Yes, your assumption is correct, for details on your specific case refer to @NobbZ response:

1 Like

I’ve been burned by this before. I wish the behavior can be changed slightly so that it only prints the string if every character is a printable character instead of any character is printable.

1 Like

That would break IO lists.

1 Like

That is how it is. Adding any non printable character to a list will make it not print:

iex(1)> 'hello'
'hello'
iex(2)> 'hello' ++ [0]
[104, 101, 108, 108, 111, 0]
3 Likes

We are talking about String.Chars, not Inspect protocoll here.

iex(1)> to_string 'hello'
"hello"
iex(2)> to_string ('hello' ++ [0])
<<104, 101, 108, 108, 111, 0>>
iex(3)> IO.puts v(2)
hello^@
:ok
1 Like

A slightly less verbose and very debug-friendly command I find myself using all the time: IO.inspect(l1, label: "l1") (will print l1: [23, 13, 6, 3, 87, 2, 1]).

  • you don’t have to remember to inspect in your string interpolation
  • it returns the inspected value as well, so you can easily pipe it anywhere in your code

Example:

"abc"
|> String.upcase()
|> IO.inspect(label: "upcase")
|> String.reverse()
|> IO.inspect(label: "reverse")
1 Like