jonnifyelixir
F3 / F3.06 / defimpl

F3.06 · part 2 of 3

Implementing for a struct

defimpl Protocol, for: Struct gives the bodies a call resolves to. Each type has its own block, and together they form a dispatch table the runtime indexes by the value's type. The protocol stays a list of signatures; the implementations carry the work.

The portal implements Portal.Summary for three entities — User, Session, and Lesson. One call, three bodies. Choose a value and watch the matching implementation run and return its own summary.

The dispatch table

Three defimpl blocks register three implementations under one protocol. A call carries the value to the block whose type matches, runs that body, and returns its result. Choose a value and see which row lights up.

The incoming value · select one

INCOMING VALUE %User{email: "ada@portal.dev", role: :student} DISPATCH TABLE · ONE defimpl PER TYPE defimpl Portal.Summary, for: User runs defimpl Portal.Summary, for: Session runs defimpl Portal.Summary, for: Lesson runs "ada@portal.dev · student"

      

Adding a fourth entity means adding a fourth defimpl — the protocol and the three existing blocks stay untouched. The behaviour grows by addition, not by editing a central function.

Writing the implementations

Inside a block, the struct name is short: for: User resolves to the full module. Each summarize/1 pattern-matches the fields it needs and returns a string — the same function name, a body shaped to the type.

defimpl Portal.Summary, for: User do
  def summarize(%User{email: e, role: r}), do: "#{e} \u00b7 #{r}"
end

defimpl Portal.Summary, for: Session do
  def summarize(%Session{id: id}), do: "session #{id} \u00b7 active"
end

defimpl Portal.Summary, for: Lesson do
  def summarize(%Lesson{id: id, minutes: m}), do: "lesson #{id} \u00b7 #{m} min"
end

The idea

One operation over many types, where adding a type does not touch the operation or the other types.

In Elixir

defimpl per struct: the dispatch table grows by addition — open for extension, closed for modification.

Next: behaviours and callbacks — the compile-time counterpart, a contract a module promises to fulfil.

References

Primary sources for this lesson, and where it connects in the course.

Sources

Related in this course