Problems and Solutions: Elixircards coding quiz at Code Elixir LDN 2019

  • Question
           list = [a: 1, b: 2]
    # what will this return
    [{"foo", "bar"} | list]


  • Answer
[{"foo", "bar"}, {:a, 1}, {:b, 2}]
  • Description

When a list in Elixir contains tuples, where the first element is an atom and the second element is a value of any term, it is considered a keyword list. Keyword lists have a special visual representation, and the square brackets can be omitted if the keyword list is the last argument of a function or macro call, or is the last element in a tuple.

That might sound kinda odd and rather convoluted, but there is rhyme and reason.

For instance when adding a dependency to the list of dependencies in a project mix-file, it is usually done as a two tuple; first element consisting of the identifier for the dependency as an atom, the second element being the requested version.

{:ex_doc, "~> 0.19"}

When we need to specify options for a dependency we can do so by using a three tuple instead; and here we use a list with our options. In the case of ExDoc we do not need it during our applications runtime, and we would not like it to be part of anything but the development environment. We can inform the system of these requirements by passing in our keyword list like this:

{:ex_doc, "~> 0.19", [{:only, :dev}, {:runtime, false}]}

Because the list consist of two tuples where the first element is an atom, we rewrite the list as such:

{:ex_doc, "~> 0.19", [only: :dev, runtime: false]}

And because we can omit the square brackets when the keyword list is the final element of the tuple, we can further rewrite it like this:

{:ex_doc, "~> 0.19", only: :dev, runtime: false}

Note that it is still a three-tuple, and all the above representations are the same; only the visual representation changes. This trick is used in other places throughout Elixir; for instance defstruct is really a macro that takes one argument: a keyword list.

defmodule Order do
  defstruct id: nil, item: nil, amount: 0

Other notable examples are the config/3 macro, and the use/2 macro which allows us to pass supervision options into a GenServer specification like this:

use GenServer, restart: :transient, shutdown: 5_000

Read more about the Elixir syntax in the Elixir Syntax Reference.

Can you find other examples where we see this in Elixir?—and if you find this interesting please consider joining us at Code Elixir LDN July 18.