Protocols and Structs

Elixir doesn’t have classes, but (perhaps surprisingly) it does have user-defined types. It pulls off this magic using structs and a few conventions.

Let’s play with a simple struct. Here’s the definition:

protocols/basic.exs
 defmodule​ Blob ​do
  defstruct ​content:​ nil
 end

And here we use it in IEx:

 iex>​ c ​"​​basic.exs"
 [Blob]
 iex>​ b = %Blob{​content:​ 123}
 %Blob{content: 123}
 iex>​ inspect b
 "%Blob{content: 123}"

It looks for all the world as if we’ve created some new type, the blob. But that’s only because Elixir is hiding something from us. By default, inspect recognizes structs. If we turn this off using the structs: false option, inspect reveals the true nature of our blob value:

 iex>​ inspect b, ​structs:​ false
 "%{__struct__: Blob, content: 123}"

A struct value is actually just a map with the key __struct__ referencing the struct’s module (Blob in this case) and the remaining elements containing the keys and values for this instance. The inspect implementation for maps checks for this—if you ask it to inspect a map containing a key __struct__ that references a module, it displays it as a struct.

Many built-in types in Elixir are represented as structs internally. It’s instructive to try creating values and inspecting them with structs: false.