All posts

Elixir Protocols for new developers

This and the other “Deck” posts are a repurposing of flashcard study decks to Q&A blog posts. Google was not showing love to this content as a set of flashcards and I didn’t want to delete them entirely, I hope you find it useful.

Protocols enable polymorphism in Elixir, what is polymorphism?

It is the ability to implement the same function with different behavior based on the data-type provided to the method.

How do Protocols enable polymorphism?

By providing an interface to group implementations of the same method on different data types.

How are protocols defined?

First you need to define the protocol with defprotcol:

defprotocol First do 
 def first(data) 
end

And then individual implementations for each type. The below implementations are for Tuple and Map:

defimpl First, for: Tuple do 
 def first(tuple), do: elem(tuple, 0) 
end 

defimpl First, for: Map do 
  def first_key_and_value(map) do 
   keys = Map.keys(map) 
   key = List.first(keys) 
   value = map[key] 
   "#{key}: #{value}" 
  end 
  
  def first(map), do: first_key_and_value(map)
end

How do you invoke a Protocol after it is defined and implemented?

For the previous example we would reference the protocol and invoke the method using dot notation and pass a data type to the method that has an implementation for the protocol:

First.first({4, 6, 12}) 
=> 4
First.first(%{name: "bob", email: "bobo@email.com"}) 
=> "name: bob"

Where are protocols used in the Elixir ecosystem?

One example is the Enum module. The Enum modules functions can operate successfully on a List, Map, or Range.

Which data types can implement a Protocol?

Atom, BitString, Float, Function, Integer, List, Map, PID, Port, Reference, Struct, Tuple.

How do protocols allow for cleaner code?

They provide another means of code organization. Any time you need the same method with different behavior, you have the option to either look for an existing protocol to add a new implementation for or to create a new protocol and extract any existing behavior into the implementations.

Do Structs require their own Protocol implementation?

Yes. Structs share a lot of behavior with maps, but each struct requires its own protocol implementation.

When implementing a protocol inside a struct, do you need to pass the for: option?

No. See the example below:

defmodule User do 
 defstruct [:email, :name] 

 defimpl Size do 
  def size(%User{}), do: 2 
 end 
end

How do you fallback to a default implementation if a protocol is invoked that doesn't have an implementation for that type?

Use the @fallback_to_any attribute, ex:

defprotocol First do 
  @doc "GET the first value from collections" 
  @fallback_to_any true 
  def first(data) 
end

And then implement first for Any

defimpl First, for: Any do 
  def first(_), do: nil 
end

More Elixir lang decks