Elixir by Example

Keyword Lists

Edit any cell and run it in your browser Download source

A keyword list is a list of {atom, value} tuples, with special syntax. It's how Elixir passes options.

opts = [timeout: 5000, retries: 3]
IO.inspect(opts)
IO.inspect(opts == [{:timeout, 5000}, {:retries, 3}])
[timeout: 5000, retries: 3]
true

Read values with opts[:key] or the Keyword module.

IO.inspect(opts[:timeout])
IO.inspect(Keyword.get(opts, :verbose, false))
IO.inspect(Keyword.fetch(opts, :retries))
5000
false
{:ok, 3}

Unlike maps, keys are ordered and may repeat. The first occurrence wins on lookup.

dup = [level: :info, level: :debug]
IO.inspect(dup[:level])
IO.inspect(Keyword.get_values(dup, :level))
:info
[:info, :debug]

Keyword.put/3 replaces all existing entries for a key; Keyword.merge/2 applies overrides.

IO.inspect(Keyword.put(dup, :level, :warn))
defaults = [timeout: 1000, retries: 1, verbose: false]
IO.inspect(Keyword.merge(defaults, opts))
[level: :warn]
[verbose: false, timeout: 5000, retries: 3]

When a keyword list is the last argument, the brackets are optional. That's why if and def accept do:.

IO.inspect(String.split("a b c", " ", parts: 2))
IO.inspect(if(true, do: "yes", else: "no"))
["a", "b c"]
"yes"

Keyword.validate!/2 rejects unknown options and fills in defaults, so typos fail loudly.

IO.inspect(Keyword.validate!([retries: 5], retries: 1, timeout: 1000))

try do
  Keyword.validate!([retires: 5], retries: 1, timeout: 1000)
rescue
  e in ArgumentError -> IO.puts("ArgumentError: " <> Exception.message(e))
end
[timeout: 1000, retries: 5]
ArgumentError: unknown keys [:retires] in [retires: 5], the allowed keys are: [:retries, :timeout]

Pitfall: don't pattern match on keyword lists like [timeout: t] = opts. It only matches if the list has exactly those keys in exactly that order. Use Keyword.get/3 or Keyword.validate!/2.