Are these keyword list syntaxes equivalent?

I have a keyword list

iex()> zodiacs = [{120, "cap"}, {218, "aqu"}, {320, "pis"}, {420, "ari"}, {521, "tau"}]
[{120, "cap"}, {218, "aqu"}, {320, "pis"}, {420, "ari"}, {521, "tau"}]

with the special syntax

iex()> zodiacs = [120: "cap", 218: "aqu", 320: "pis", 420: "ari", 521: "tau"]
** (SyntaxError) iex:8: unexpected token: ":" (column 15, codepoint U+003A)

According to the docs

Elixir supports a special syntax for defining such lists: [key: value]. Underneath it maps to the same list of tuples as above.

but also

Keyword lists are important because they have three special characteristics:

  • Keys must be atoms.
  • Keys are ordered, as specified by the developer.
  • Keys can be given more than once.

So if both syntaxes are the same the why the second code doesn’t work? Or is the first code just a list of tuples (different than keyword list) because the first key in each tuple is not an atom?

[120: “cap”] == [{:120, “cap”}]. A bare number is not equivalent to the atom with those digits.

1 Like

Testing this in IEX it looks like atoms can’t start with a digit :confused: but according to Programming Elixir atoms can be written…

…using a leading colon (:), followed by an atom word or an Elixir operator. An atom word is a sequence of letters, digits, underscores, and @ signs). It may end with an exclamation point or a question mark.

1 Like

:120 is not valid elixir. The erlang atom '120' has to et written as :"120" in elixir. But in a sense you are right, one can’t use non-atoms as keys for that syntactic sugar but one has to use atoms as described in the docs.

1 Like

The full rules for (unquoted) atoms are

ATOM_END = [?!]
ATOM_MIDDLE = [0-9a-zA-Z@_]
ATOM_START = [a-zA-Z_]

I had to figure out the rules when writing the plugin. The @ is allowed specifically to handle long names for distributed Erlang.


Huh, I did not know elixir allowed an un-quoted atom to end with a ? or a !, interesting, I wonder where that is used…

It used when referring functions or map keys that have ? or ! on the end, so :valid? or :fetch!.

For example, in Ecto.Changesets, valid? is a field, not a function like in ActiveRecord::Base You can match against it to match valid changesets only as follows:

def my_func(%Ecto.Changeset{valid?: true}), do: ...

Ahh, that does indeed make sense, those usages completely slipped my mind. ^.^

1 Like