String to existing atom unless atom already

There’s a variable, which might come as either atom or string (binary in erlang parlance). I need to use it to Access a Keyword list with atoms as keys. I surely can put a conditional around the String.to_existing_atom/1 so that I don’t get an exception when the variable is an atom already. But maybe there’s a better way to deal with such situation?

I don’t think there is such a way, you’re better off just writing two function variants for atom and binary argument.

4 Likes

The worst I could come up with is String.to_existing_atom(to_string(foo)) :slight_smile:

1 Like

I think this is what @dimitarvp suggested:

hash_map = %{foo: "Foo", bar: "Bar"}

defmodule HashMap do
  def get(hash_map, key) when is_atom(key), do: hash_map[key]
  def get(hash_map, key) when is_binary(key), do: hash_map[String.to_existing_atom(key)]  
end

{atom, string} = {hash_map |> HashMap.get(:foo), hash_map |> HashMap.get("bar")}

# Output
# {"Foo", "Bar"}

If you pass non existent keys in, you get nil values back, no exception.


P.S. I just wrote it for practice, as I am learning Elixir.

1 Like

If you’re only looking in a Keyword list, you could bypass the Access behaviour and do your own lookup to avoid needing to turn a string into an atom at all.

def lookup(keyword, key) when is_atom(key) do
  Keyword.get(keyword, key)
end

def lookup(keyword, key) when is_binary(key) do
  # just an example of one way to do this approach
  if pair = Enum.find(keyword, fn {k, _v} -> Atom.to_string(k) == key end) do
    elem(pair, 1)
  end
end