Elixir 1.14's new `:optional` option when deriving the `Inspect` protocol
I recently discovered a new option for the Inspect
protocol introduced in
Elixir 1.14 — the :optional
option.
Deriving the Inspect
protocol
When we derive the Inspect
protocol for a struct, we have three options we can
use to change how the struct is presented:
- Only show specific fields,
- Show everything except some fields, and
- Since Elixir 1.14, make fields optional — only showing them if they differ from their default values.
Let’s take a User
struct as an example:
defmodule User do
defstruct [:name, :email, admin: false]
end
By default, when we inspect a User
struct, we’ll see this:
iex> %User{name: "Frodo", email: "frodo@baggins.com"}
%User{name: "Frodo", email: "frodo@baggins.com", admin: false}
:only
certain fields
Let’s now derive the Inspect
protocol and tell it to show only the :name
:
defmodule User do
@derive {Inspect, only: [:name]} # <= add this
defstruct [:name, :email, admin: false]
end
Now, let’s see what the User
struct looks like:
iex> %User{name: "Frodo", email: "frodo@baggins.com"}
#User<name: "Frodo", ...>
It only shows the name. Very nice.
Everything :except
certain fields
Likewise, we can show everything except a field:
defmodule User do
@derive {Inspect, except: [:name]} # <= add this
defstruct [:name, :email, admin: false]
end
Let’s see what that looks like:
iex> %User{name: "Frodo", email: "frodo@baggins.com"}
#User<email: "frodo@baggins.com", admin: false, ...>
As you can see, that printed all the fields (including the default ones) except the name.
Making some fields :optional
Finally, Elixir 1.14 introduced the :optional
option:
defmodule User do
@derive {Inspect, optional: [:admin]} # <= add this
defstruct [:name, :email, admin: false]
end
We set the :admin
to be optional. Let’s see how that looks:
iex> %User{name: "Frodo", email: "frodo@baggins.com"}
%User{name: "Frodo", email: "frodo@baggins.com"}
As you can see, the User
struct doesn’t show the admin
field because we’re
using the default.
But what if we change it to something else?
iex> %User{name: "Frodo", email: "frodo@baggins.com", admin: true}
%User{name: "Frodo", email: "frodo@baggins.com", admin: true}
Aha! Now the Inspect
protocol is showing us the admin field!
When would I use that?
Turns out Elixir sometimes uses that option to hide deprecated fields. And it can be used in Ecto to hide associations when they’re not loaded!
Pretty neat, huh?