Override Access.get to support using brackets to access an index of a list

I want to use get_in(data, keys) for a nested map with some values having a list with maps.

map = %{a: 1, aa: [%{b: 2}, %{bb: 22}], aaa: 111}
get_in(map, [:aa, 1, :bb]) # => 22

Is there a way to override Access.get to return Enum.at(list, key)?

  def get(list, key, _default) when is_list(list) and is_integer(key) do
    raise ArgumentError, """
    the Access module does not support accessing lists by index, got: #{inspect(key)}

    Accessing a list by index is typically discouraged in Elixir, \
    instead we prefer to use the Enum module to manipulate lists \
    as a whole. If you really must access a list element by index, \
    you can use Enum.at/2 or the functions in the List module\
    """
  end
  def get(list, key, _default) when is_list(list) and is_integer(key) do
    Enum.at(list, key)
  end

I found this conversation on Google Groups from 2023 with @zachdaniel @wojtekmach to understand @josevalim’s reasoning, but what would be the idiomatic way to do this?

https://groups.google.com/g/elixir-lang-core/c/cS5EJ2Qu4uc

You want Access.at/1

1 Like

Thanks, this works for me.

map = %{a: 1, aa: [%{b: 2}, %{bb: 22}], aaa: 111}
path = [:aa, 1, :bb]
path = Enum.map(path, fn key ->
  if is_integer(key) do
    Access.at(key)
  else
    key
  end
end)

get_in(map, path) # => 22