Key-value confusion

I sometimes run into problems with incompatibilities between the format of a map and they way one extracts a value with a key. I wrote the little function get_value_of_key(key, map) below to help with this. Question: is this OK, or instead a really bad idea?

efmodule Koko.Utility do

  @doc """
  get_value_of_key(key, map) gets the value
  of the key in the given map regardless
  of the format (string, atom).

  Let m = %{foo: 1, bar: 2}. Then
     m[:foo] == 1
     m["foo"] == 1
  Let m = %{"foo" => 1, "bar" => 2}.  Then
     m[:foo] == 1, m["foo"] == 1
  """
  def get_value_of_key(key, map) do
    key = if is_atom(key) do
      to_string(key)
    else
      key
    end
    map[key] || map[String.to_atom(key)]
  end

end

as mention in this post:

the best way to get a key from a map its to do a partern matching on the function def, example

def do_something_with_map_key({:foo, foo} = map} do
# do something
end
2 Likes

Thankyou! That is a much better way.

1 Like

No, this is not okay, since you are using String.to_atom/1, which you really shouldn’t. Also the better way to solve this problem is, to simply remember the correct type of the key. There are reasons why one uses atom-keys here and string keys there. At least there are reasons most of the time…

3 Likes

Thankyou! I had feeling it was a bad idea.

I’ll be honest with you, I think it’s a bad idea.

My gut tells me that external data = string, internal data = atom.

Also, I remember HashWithIndifferentAccess from Rails. It was so hard teaching junior programmers things because of that class.

1 Like

I appreciate the voice of experience :smile: – and good rule of thumb. (back to the drawing boards)

@WolfDan I think your pattern match is supposed to look like this?

    def do_something_with_map_key(%{foo: foo} = map} do
      # do something 
    end

# Or, for non-atom keys:
    def do_something_with_map_key(%{1 => foo} = map} do
      # do something 
    end
2 Likes