Ninigi

Ninigi

Is there a way to inspect a list of integers without accidentally ending up with a charlist?

Story

skip this if you are not interested in the Why

Today I was working on a rewrite of a feature, heavily relying on a 3rd Party HTTP API response, no tests available yet, so I decided to bite the bullet and do what I felt like I had to do. Fortunately all the API connections are done in a way, so at least parts of the return values can be mocked, and no actual request has to be made, but you need to provide a valid response.
The response in this case happened to be a big map - 140+x lines of code after parsing the JSON response and running it through the Elixir Formatter. So I thought I was clever, and ran a real example, writing the response to a txt file, and using File.write!(path, inspect(response), so I could copy-paste a real response into a fixture. The problem was that one part %{..., something_ids: Enum.map(raw["something"], & &1["id"]), ... returned [123], which everyone intuitively knows equals to '{' when inspected, because ?{ == [123].
I was running into weird bugs, because '{' was passed down to an ecto query, which would of course find nothing with those ids, and I was banging my head against the wall, why the hell the changeset error was “invalid association” (a lot more going on behind the scenes, but you get the idea). So, I put IEx.pry into multiple places, and saw the error in the fixture. I did not think much about it, replaced it with the value I knew it should be and… It still did not work.
Of course I put IO.inspect(something_ids) in multiple places and always got '{'. At that time I was already stressed out, because that was NOT the bug I was hunting, this was something in my test setup!

After some more head-banging-against-the-wall, I pasted a screen recording into our developer chat, asking what’s going on, and only 1 minute later someone said "does this explain anything? ?{ #=> [123], and I was very ready to bang my head even more, this time voluntarily, for being such an idiot.

Problem

I think I have a basic understanding of why a list of integers might be displayed as a string, but it gave us problems debugging multiple time now - in fact the guy who gave me the clue, was someone I had given the same clue a few months ago.
Not only debugging tends to get harder, if your outputs are displayed differently than what you would expect, but also admin UIs: I frequently use inspect in interfaces, for example to display exq failed jobs and the arguments, error message etc.

Question

I understand this might be a problem with internal representations, but is there any way to display a list of integers (that could, or could not) be a list of characters?

Sidenote

The universe decided to give me a headache with this, because incidentally, the original bug had the same error message.

Marked As Solved

nathanl

nathanl

Take a look at Inspect.Opts and the :charlists option.

[123, 124] |> IO.inspect(charlists: :as_charlists) # => '{|'
[123, 124] |> IO.inspect(charlists: :as_lists) # => [123, 124]
[123, 124] |> IO.inspect(charlists: :infer) # => '{|'

When the default :infer , the list will be printed as a charlist if it is printable, otherwise as list. See List.ascii_printable?/1 to learn when a charlist is printable.

10
Post #2

Also Liked

NobbZ

NobbZ

You can pipe into everything… And the nice thing about IO.inspect is, its an identity function. It will return exactly what you gave it. Together with the :label option, its ideal to do ad-hoc debugging of pipelines:

1
|> IO.inspect(label: "before")
|> Kernel.+(1)
|> IO.inspect(label: "after")
NobbZ

NobbZ

You shouldn’t use IEx.i/1 from within code…

NobbZ

NobbZ

Why should I?

I use IEx.i/1 from iex, while I use IO.inspect/2 from within my code.

Where Next?

Popular in Questions Top

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Other popular topics Top

mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43757 214
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

We're in Beta

About us Mission Statement