# `Collectable`
[🔗](https://github.com/elixir-lang/elixir/blob/v1.20.0-rc.3/lib/elixir/lib/collectable.ex#L5)

A protocol to traverse data structures.

The `Enum.into/2` function uses this protocol to insert an
enumerable into a collection:

    iex> Enum.into([a: 1, b: 2], %{})
    %{a: 1, b: 2}

## Why Collectable?

The `Enumerable` protocol is useful to take values out of a collection.
In order to support a wide range of values, the functions provided by
the `Enumerable` protocol do not keep shape. For example, passing a
map to `Enum.map/2` always returns a list.

This design is intentional. `Enumerable` was designed to support infinite
collections, resources and other structures with fixed shape. For example,
it doesn't make sense to insert values into a `Range`, as it has a
fixed shape where only the range limits and step are stored.

The `Collectable` module was designed to fill the gap left by the
`Enumerable` protocol. `Collectable.into/1` can be seen as the opposite of
`Enumerable.reduce/3`. If the functions in `Enumerable` are about taking values out,
then `Collectable.into/1` is about collecting those values into a structure.

## Examples

To show how to manually use the `Collectable` protocol, let's play with a
simplified implementation for `MapSet`.

    iex> {initial_acc, collector_fun} = Collectable.into(MapSet.new())
    iex> updated_acc = Enum.reduce([1, 2, 3], initial_acc, fn elem, acc ->
    ...>   collector_fun.(acc, {:cont, elem})
    ...> end)
    iex> collector_fun.(updated_acc, :done)
    MapSet.new([1, 2, 3])

To show how the protocol can be implemented, we can again look at the
simplified implementation for `MapSet`. In this implementation "collecting" elements
simply means inserting them in the set through `MapSet.put/2`.

    defimpl Collectable, for: MapSet do
      def into(map_set) do
        collector_fun = fn
          map_set_acc, {:cont, elem} ->
            MapSet.put(map_set_acc, elem)

          map_set_acc, :done ->
            map_set_acc

          _map_set_acc, :halt ->
            :ok
        end

        initial_acc = map_set

        {initial_acc, collector_fun}
      end
    end

So now we can call `Enum.into/2`:

    iex> Enum.into([1, 2, 3], MapSet.new())
    MapSet.new([1, 2, 3])

# `command`

```elixir
@type command() :: {:cont, term()} | :done | :halt
```

# `t`

```elixir
@type t() :: term()
```

All the types that implement this protocol.

# `into`

```elixir
@spec into(t()) ::
  {initial_acc :: term(), collector :: (term(), command() -&gt; t() | term())}
```

Returns an initial accumulator and a "collector" function.

Receives a `collectable` which can be used as the initial accumulator that will
be passed to the function.

The collector function receives a term and a command and injects the term into
the collectable accumulator on every `{:cont, term}` command.

`:done` is passed as a command when no further values will be injected. This
is useful when there's a need to close resources or normalizing values. A
collectable must be returned when the command is `:done`.

If injection is suddenly interrupted, `:halt` is passed and the function
can return any value as it won't be used.

For examples on how to use the `Collectable` protocol and `into/1` see the
module documentation.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
