/ elixir

Hash Keys Manipulations

Atoms, strings and numbers are three different things. But when type coercion enters the game, some languages can be confusing.

Elixir: Atoms And Strings

Unsurprisingly this map:

%{foo: 10}

is not the same as this map:

%{"foo" => 10}

This of course is easy to see here, but when maps are not defined in code it can be confusing. For example this code:

input = IO.stream(:stdio, :line)
        |> Enum.at(0)
        |> String.trim


Map.get(%{p: "Hello"}, input)
|> IO.puts

Won't print "Hello" even if we run it with the following input:

echo p | elixir demo.elxrs

The fix is easy once you realize there's a problem:

input = IO.stream(:stdio, :line)
        |> Enum.at(0)
        |> String.trim


Map.get(%{"p" => "Hello"}, input)
|> IO.puts

Auto Stringify Hash Keys

The above behaviour is surprising when coming from languages that will automatically stringify hash keys. Here's JavaScript for example:

t = { 2: "Hello" }

console.log(t[2])
console.log(t["2"])

Both lines print "Hello".

Perl is another example. Here again both lines will print "Hello":

use strict;
use warnings;
use v5.18;

my %t = ( 2 => "Hello" );

say $t{2};
say $t{"2"};

And Then There's Rails

This one took me the longest to understand. In ruby hash keys are not stringified:

t = { p: "Hello" }
puts t["p"]

Won't print anything.

But then Rails came and added Hash#with_indifferent_access. So this one does print Hello:

t = { p: "Hello" }.with_indifferent_access
puts t["p"]

Bottom line it's important to remember what language you're in and that language's specifics, especially when working with structures that feel similiar.