Unexpected Keyword.merge behavior (elixir 1.9.4)

Hi,

I’m getting an unexpected result when I merge keyword lists with list values. My understanding is that when a keyword appears in both lists, the result should contain the value in the second keyword list for the conflicting key. However, I found a scenario where it seems like value is getting transformed to something else entirely:

iex(5)> Keyword.merge([a: []], [a: [1]]) # this works as I expect
[a: [1]]
iex(6)> Keyword.merge([a: []], [a: [6]]) # ditto
[a: [6]]
iex(7)> Keyword.merge([a: []], [a: [7]]) # but here 7 becomes '\a'?
[a: '\a']
iex(8)> Keyword.merge([a: []], [a: [8]]) # etc..
[a: '\b']
iex(9)> Keyword.merge([a: []], [a: [9]]) # etc..
[a: '\t']
iex(10)> Keyword.merge([a: []], [a: [10]]) # etc..
[a: '\n']

Is this supposed to happen and if so what’s going on under the hood?

Hello and welcome,

It’s the charlist challenge, once You understand this, You can go to the next level :slight_smile:

iex> [65, 66, 67]
'ABC'
iex> [65, 66, 67, 0]
[65, 66, 67, 0]
iex> [7]
'\a'
iex> [7] == '\a'
true

Charlist are just list of codepoints, if Elixir receive a list of integers, it will try to print it as readable characters, if not, it will print the list. In case You want to inspect…

iex> IO.inspect [65, 66, 67], charlists: :as_lists
[65, 66, 67]
iex> IO.inspect [65, 66, 67], charlists: :as_charlists
'ABC'
6 Likes

I call this the ‘one footgun in elixir’, but really it’s more like a toenail clipper

2 Likes

Got it! Thanks for the explanation :slight_smile:. Indeed, it looks like '\a' behaves exactly like [7] under the hood.

Here’s some more context just in case someone else stumbles upon this for the same reason I did:

I was investigating this behavior because I had a more general bug where I was merging keyword lists and passing the result into another function. When I did that I got a signature mismatch error, which I thought was happening because one of the values was getting transformed as I explained above.

This was a red herring though – the actual mismatch was due to the fact that merging keyword lists doesn’t guarantee the result to have the same keyword order.

2 Likes

They don’t I believe because it’s generally valid to lazily tombstone (as nil) or update a keyword list value by pretending values

1 Like