# Elixir v1.10.3 Access behaviour View Source

Key-based access to data structures.

The `Access` module defines a behaviour for dynamically accessing keys of any type in a data structure via the `data[key]` syntax.

`Access` supports keyword lists (`Keyword`) and maps (`Map`) out of the box. The key can be of any type and it returns `nil` if the key does not exist:

    iex> keywords = [a: 1, b: 2]
    iex> keywords[:a]
    1
    iex> keywords[:c]
    nil

    iex> map = %{a: 1, b: 2}
    iex> map[:a]
    1

    iex> star_ratings = %{1.0 => "★", 1.5 => "★☆", 2.0 => "★★"}
    iex> star_ratings[1.5]
    "★☆"

This syntax is very convenient as it can be nested arbitrarily:

    iex> keywords = [a: 1, b: 2]
    iex> keywords[:c][:unknown]
    nil

This works because accessing anything on a `nil` value, returns `nil` itself:

    iex> nil[:a]
    nil

The access syntax can also be used with the `Kernel.put_in/2`, `Kernel.update_in/2` and `Kernel.get_and_update_in/2` macros to allow values to be set in nested data structures:

    iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
    iex> put_in(users["john"][:age], 28)
    %{"john" => %{age: 28}, "meg" => %{age: 23}}

> Attention! While the access syntax is allowed in maps via `map[key]`, if your map is made of predefined atom keys, you should prefer to access those atom keys with `map.key` instead of `map[key]`, as `map.key` will raise if the key is missing. This is important because, if a map has a predefined set of keys and a key is missing, it is most likely a bug in your software or a typo on the key name. For this reason, because structs are predefined in nature, they only allow the `struct.key` syntax and they do not allow the `struct[key]` access syntax. See the `Map` module for more information.

## Nested data structures

Both key-based access syntaxes can be used with the nested update functions and macros in `Kernel`, such as `Kernel.get_in/2`, `Kernel.put_in/3`, `Kernel.update_in/3`, `Kernel.pop_in/2`, and `Kernel.get_and_update_in/3`.

For example, to update a map inside another map:

    iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
    iex> put_in(users["john"].age, 28)
    %{"john" => %{age: 28}, "meg" => %{age: 23}}

This module provides convenience functions for traversing other structures, like tuples and lists. These functions can be used in all the `Access`-related functions and macros in `Kernel`.

For instance, given a user map with the `:name` and `:languages` keys, here is how to deeply traverse the map and convert all language names to uppercase:

    iex> languages = [
    ...>   %{name: "elixir", type: :functional},
    ...>   %{name: "c", type: :procedural}
    ...> ]
    iex> user = %{name: "john", languages: languages}
    iex> update_in(user, [:languages, Access.all(), :name], &String.upcase/1)
    %{
      name: "john",
      languages: [
        %{name: "ELIXIR", type: :functional},
        %{name: "C", type: :procedural}
      ]
    }

See the functions `key/1`, `key!/1`, `elem/1`, and `all/0` for some of the available accessors.

# Link to this section Summary

## Types

access_fun(data, get_value)
any_container()
container()
get_and_update_fun(data, get_value)
get_fun(data, get_value)
key()
nil_container()
t()
value()

## Functions

all()

Returns a function that accesses all the elements in a list.

at(index)

Returns a function that accesses the element at `index` (zero based) of a list.

elem(index)

Returns a function that accesses the element at the given index in a tuple.

fetch(container, key)

Fetches the value for the given key in a container (a map, keyword list, or struct that implements the `Access` behaviour).

fetch!(container, key)

Same as `fetch/2` but returns the value directly, or raises a `KeyError` exception if `key` is not found.

filter(func)

Returns a function that accesses all elements of a list that match the provided predicate.

get(container, key, default \\ nil)

Gets the value for the given key in a container (a map, keyword list, or struct that implements the `Access` behaviour).

get_and_update(container, key, fun)

Gets and updates the given key in a `container` (a map, a keyword list, a struct that implements the `Access` behaviour).

key(key, default \\ nil)

Returns a function that accesses the given key in a map/struct.

key!(key)

Returns a function that accesses the given key in a map/struct.

pop(container, key)

Removes the entry with a given key from a container (a map, keyword list, or struct that implements the `Access` behaviour).

## Callbacks

fetch(term, key)

Invoked in order to access the value stored under `key` in the given term `term`.

get_and_update(data, key, function)

Invoked in order to access the value under `key` and update it at the same time.

pop(data, key)

Invoked to "pop" the value under `key` out of the given data structure.

# Link to this section Types

Link to this type

# access_fun(data, get_value)

View Source

## Specs

    access_fun(data, get_value) ::
      get_fun(data, get_value) | get_and_update_fun(data, get_value)

Link to this type

# any_container()

View Source

## Specs

    any_container() :: any()

Link to this type

# container()

View Source

## Specs

    container() :: keyword() | struct() | map()

Link to this type

# get_and_update_fun(data, get_value)

View Source

## Specs

    get_and_update_fun(data, get_value) ::
      (:get_and_update, data, (term() -> term()) ->
         {get_value, new_data :: container()} | :pop)

Link to this type

# get_fun(data, get_value)

View Source

## Specs

    get_fun(data, get_value) ::
      (:get, data, (term() -> term()) -> {get_value, new_data :: container()})

Link to this type

# key()

View Source

## Specs

    key() :: any()

Link to this type

# nil_container()

View Source

## Specs

    nil_container() :: nil

Link to this type

# t()

View Source

## Specs

    t() :: container() | nil_container() | any_container()

Link to this type

# value()

View Source

## Specs

    value() :: any()

# Link to this section Functions

Link to this function

# all()

View Source

## Specs

    all() :: access_fun(data :: list(), get_value :: list())

Returns a function that accesses all the elements in a list.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

## Examples

    iex> list = [%{name: "john"}, %{name: "mary"}]
    iex> get_in(list, [Access.all(), :name])
    ["john", "mary"]
    iex> get_and_update_in(list, [Access.all(), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {["john", "mary"], [%{name: "JOHN"}, %{name: "MARY"}]}
    iex> pop_in(list, [Access.all(), :name])
    {["john", "mary"], [%{}, %{}]}

Here is an example that traverses the list dropping even numbers and multiplying odd numbers by 2:

    iex> require Integer
    iex> get_and_update_in([1, 2, 3, 4, 5], [Access.all()], fn num ->
    ...>   if Integer.is_even(num), do: :pop, else: {num, num * 2}
    ...> end)
    {[1, 2, 3, 4, 5], [2, 6, 10]}

An error is raised if the accessed structure is not a list:

    iex> get_in(%{}, [Access.all()])
    ** (RuntimeError) Access.all/0 expected a list, got: %{}

Link to this function

# at(index)

View Source

## Specs

    at(integer()) :: access_fun(data :: list(), get_value :: term())

Returns a function that accesses the element at `index` (zero based) of a list.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

## Examples

    iex> list = [%{name: "john"}, %{name: "mary"}]
    iex> get_in(list, [Access.at(1), :name])
    "mary"
    iex> get_in(list, [Access.at(-1), :name])
    "mary"
    iex> get_and_update_in(list, [Access.at(0), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {"john", [%{name: "JOHN"}, %{name: "mary"}]}
    iex> get_and_update_in(list, [Access.at(-1), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {"mary", [%{name: "john"}, %{name: "MARY"}]}

`at/1` can also be used to pop elements out of a list or a key inside of a list:

    iex> list = [%{name: "john"}, %{name: "mary"}]
    iex> pop_in(list, [Access.at(0)])
    {%{name: "john"}, [%{name: "mary"}]}
    iex> pop_in(list, [Access.at(0), :name])
    {"john", [%{}, %{name: "mary"}]}

When the index is out of bounds, `nil` is returned and the update function is never called:

    iex> list = [%{name: "john"}, %{name: "mary"}]
    iex> get_in(list, [Access.at(10), :name])
    nil
    iex> get_and_update_in(list, [Access.at(10), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {nil, [%{name: "john"}, %{name: "mary"}]}

An error is raised if the accessed structure is not a list:

    iex> get_in(%{}, [Access.at(1)])
    ** (RuntimeError) Access.at/1 expected a list, got: %{}

Link to this function

# elem(index)

View Source

## Specs

    elem(non_neg_integer()) :: access_fun(data :: tuple(), get_value :: term())

Returns a function that accesses the element at the given index in a tuple.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

The returned function raises if `index` is out of bounds.

Note that popping elements out of tuples is not possible and raises an error.

## Examples

    iex> map = %{user: {"john", 27}}
    iex> get_in(map, [:user, Access.elem(0)])
    "john"
    iex> get_and_update_in(map, [:user, Access.elem(0)], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {"john", %{user: {"JOHN", 27}}}
    iex> pop_in(map, [:user, Access.elem(0)])
    ** (RuntimeError) cannot pop data from a tuple

An error is raised if the accessed structure is not a tuple:

    iex> get_in(%{}, [Access.elem(0)])
    ** (RuntimeError) Access.elem/1 expected a tuple, got: %{}

Link to this function

# fetch(container, key)

View Source

## Specs

    fetch(container(), term()) :: {:ok, term()} | :error

    fetch(nil_container(), any()) :: :error

Fetches the value for the given key in a container (a map, keyword list, or struct that implements the `Access` behaviour).

Returns `{:ok, value}` where `value` is the value under `key` if there is such a key, or `:error` if `key` is not found.

## Examples

    iex> Access.fetch(%{name: "meg", age: 26}, :name)
    {:ok, "meg"}

    iex> Access.fetch([ordered: true, on_timeout: :exit], :timeout)
    :error

Link to this function

# fetch!(container, key)

View Source (since 1.10.0)

## Specs

    fetch!(container(), term()) :: term()

Same as `fetch/2` but returns the value directly, or raises a `KeyError` exception if `key` is not found.

## Examples

    iex> Access.fetch!(%{name: "meg", age: 26}, :name)
    "meg"

Link to this function

# filter(func)

View Source (since 1.6.0)

## Specs

    filter((term() -> boolean())) :: access_fun(data :: list(), get_value :: list())

Returns a function that accesses all elements of a list that match the provided predicate.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

## Examples

    iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
    iex> get_in(list, [Access.filter(&(&1.salary > 20)), :name])
    ["francine"]
    iex> get_and_update_in(list, [Access.filter(&(&1.salary <= 20)), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {["john"], [%{name: "JOHN", salary: 10}, %{name: "francine", salary: 30}]}

`filter/1` can also be used to pop elements out of a list or a key inside of a list:

    iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
    iex> pop_in(list, [Access.filter(&(&1.salary >= 20))])
    {[%{name: "francine", salary: 30}], [%{name: "john", salary: 10}]}
    iex> pop_in(list, [Access.filter(&(&1.salary >= 20)), :name])
    {["francine"], [%{name: "john", salary: 10}, %{salary: 30}]}

When no match is found, an empty list is returned and the update function is never called

    iex> list = [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]
    iex> get_in(list, [Access.filter(&(&1.salary >= 50)), :name])
    []
    iex> get_and_update_in(list, [Access.filter(&(&1.salary >= 50)), :name], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {[], [%{name: "john", salary: 10}, %{name: "francine", salary: 30}]}

An error is raised if the predicate is not a function or is of the incorrect arity:

    iex> get_in([], [Access.filter(5)])
    ** (FunctionClauseError) no function clause matching in Access.filter/1

An error is raised if the accessed structure is not a list:

    iex> get_in(%{}, [Access.filter(fn a -> a == 10 end)])
    ** (RuntimeError) Access.filter/1 expected a list, got: %{}

Link to this function

# get(container, key, default \\ nil)

View Source

## Specs

    get(container(), term(), term()) :: term()

    get(nil_container(), any(), default) :: default when default: var

Gets the value for the given key in a container (a map, keyword list, or struct that implements the `Access` behaviour).

Returns the value under `key` if there is such a key, or `default` if `key` is not found.

## Examples

    iex> Access.get(%{name: "john"}, :name, "default name")
    "john"
    iex> Access.get(%{name: "john"}, :age, 25)
    25

    iex> Access.get([ordered: true], :timeout)
    nil

Link to this function

# get_and_update(container, key, fun)

View Source

## Specs

    get_and_update(data, key(), (value() -> {get_value, value()} | :pop)) ::
      {get_value, data}
    when data: container(), get_value: var

Gets and updates the given key in a `container` (a map, a keyword list, a struct that implements the `Access` behaviour).

The `fun` argument receives the value of `key` (or `nil` if `key` is not present in `container`) and must return a two-element tuple `{get_value, update_value}`: the "get" value `get_value` (the retrieved value, which can be operated on before being returned) and the new value to be stored under `key` (`update_value`). `fun` may also return `:pop`, which means the current value should be removed from the container and returned.

The returned value is a two-element tuple with the "get" value returned by `fun` and a new container with the updated value under `key`.

## Examples

    iex> Access.get_and_update([a: 1], :a, fn current_value ->
    ...>   {current_value, current_value + 1}
    ...> end)
    {1, [a: 2]}

Link to this function

# key(key, default \\ nil)

View Source

## Specs

    key(key(), term()) :: access_fun(data :: struct() | map(), get_value :: term())

Returns a function that accesses the given key in a map/struct.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

The returned function uses the default value if the key does not exist. This can be used to specify defaults and safely traverse missing keys:

    iex> get_in(%{}, [Access.key(:user, %{name: "meg"}), Access.key(:name)])
    "meg"

Such is also useful when using update functions, allowing us to introduce values as we traverse the data structure for updates:

    iex> put_in(%{}, [Access.key(:user, %{}), Access.key(:name)], "Mary")
    %{user: %{name: "Mary"}}

## Examples

    iex> map = %{user: %{name: "john"}}
    iex> get_in(map, [Access.key(:unknown, %{}), Access.key(:name, "john")])
    "john"
    iex> get_and_update_in(map, [Access.key(:user), Access.key(:name)], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {"john", %{user: %{name: "JOHN"}}}
    iex> pop_in(map, [Access.key(:user), Access.key(:name)])
    {"john", %{user: %{}}}

An error is raised if the accessed structure is not a map or a struct:

    iex> get_in(nil, [Access.key(:foo)])
    ** (BadMapError) expected a map, got: nil

    iex> get_in([], [Access.key(:foo)])
    ** (BadMapError) expected a map, got: []

Link to this function

# key!(key)

View Source

## Specs

    key!(key()) :: access_fun(data :: struct() | map(), get_value :: term())

Returns a function that accesses the given key in a map/struct.

The returned function is typically passed as an accessor to `Kernel.get_in/2`, `Kernel.get_and_update_in/3`, and friends.

Similar to `key/2`, but the returned function raises if the key does not exist.

## Examples

    iex> map = %{user: %{name: "john"}}
    iex> get_in(map, [Access.key!(:user), Access.key!(:name)])
    "john"
    iex> get_and_update_in(map, [Access.key!(:user), Access.key!(:name)], fn prev ->
    ...>   {prev, String.upcase(prev)}
    ...> end)
    {"john", %{user: %{name: "JOHN"}}}
    iex> pop_in(map, [Access.key!(:user), Access.key!(:name)])
    {"john", %{user: %{}}}
    iex> get_in(map, [Access.key!(:user), Access.key!(:unknown)])
    ** (KeyError) key :unknown not found in: %{name: "john"}

An error is raised if the accessed structure is not a map/struct:

    iex> get_in([], [Access.key!(:foo)])
    ** (RuntimeError) Access.key!/1 expected a map/struct, got: []

Link to this function

# pop(container, key)

View Source

## Specs

    pop(data, key()) :: {value(), data} when data: container()

Removes the entry with a given key from a container (a map, keyword list, or struct that implements the `Access` behaviour).

Returns a tuple containing the value associated with the key and the updated container. `nil` is returned for the value if the key isn't in the container.

## Examples

With a map:

    iex> Access.pop(%{name: "Elixir", creator: "Valim"}, :name)
    {"Elixir", %{creator: "Valim"}}

A keyword list:

    iex> Access.pop([name: "Elixir", creator: "Valim"], :name)
    {"Elixir", [creator: "Valim"]}

An unknown key:

    iex> Access.pop(%{name: "Elixir", creator: "Valim"}, :year)
    {nil, %{creator: "Valim", name: "Elixir"}}

# Link to this section Callbacks

Link to this callback

# fetch(term, key)

View Source

## Specs

    fetch(term :: t(), key()) :: {:ok, value()} | :error

Invoked in order to access the value stored under `key` in the given term `term`.

This function should return `{:ok, value}` where `value` is the value under `key` if the key exists in the term, or `:error` if the key does not exist in the term.

Many of the functions defined in the `Access` module internally call this function. This function is also used when the square-brackets access syntax (`structure[key]`) is used: the `fetch/2` callback implemented by the module that defines the `structure` struct is invoked and if it returns `{:ok, value}` then `value` is returned, or if it returns `:error` then `nil` is returned.

See the `Map.fetch/2` and `Keyword.fetch/2` implementations for examples of how to implement this callback.

Link to this callback

# get_and_update(data, key, function)

View Source

## Specs

    get_and_update(data, key(), (value() -> {get_value, value()} | :pop)) ::
      {get_value, data}
    when data: container() | any_container(), get_value: var

Invoked in order to access the value under `key` and update it at the same time.

The implementation of this callback should invoke `fun` with the value under `key` in the passed structure `data`, or with `nil` if `key` is not present in it. This function must return either `{get_value, update_value}` or `:pop`.

If the passed function returns `{get_value, update_value}`, the return value of this callback should be `{get_value, new_data}`, where:

- `get_value` is the retrieved value (which can be operated on before being returned)

- `update_value` is the new value to be stored under `key`

- `new_data` is `data` after updating the value of `key` with `update_value`.

If the passed function returns `:pop`, the return value of this callback must be `{value, new_data}` where `value` is the value under `key` (or `nil` if not present) and `new_data` is `data` without `key`.

See the implementations of `Map.get_and_update/3` or `Keyword.get_and_update/3` for more examples.

Link to this callback

# pop(data, key)

View Source

## Specs

    pop(data, key()) :: {value(), data} when data: container() | any_container()

Invoked to "pop" the value under `key` out of the given data structure.

When `key` exists in the given structure `data`, the implementation should return a `{value, new_data}` tuple where `value` is the value that was under `key` and `new_data` is `term` without `key`.

When `key` is not present in the given structure, a tuple `{value, data}` should be returned, where `value` is implementation-defined.

See the implementations for `Map.pop/3` or `Keyword.pop/3` for more examples.