Elixir Protocols

Welcome to a tutorial on Protocols in Elixir. 

In Elixir, Protocols are a mechanism to achieve polymorphism. Any data type has been dispatched on a protocol, as long as it implements the protocol.

Suppose we used a function called to_string in the previous chapters to convert from other types to the string type. This action is a protocol because it acts according to the input that is given without producing an error. Although this may look as if dealing with pattern matching functions, as we proceed further, it will look different.

Let’s consider the example below to understand the protocol mechanism.

We will create a protocol that will display if the given input is empty or not. Let’s call this protocol blank?.

 

Defining a Protocol

In Elixir, we can define a protocol as shown below.

defprotocol Blank do
   def blank?(data)
end

In the above code, we don't need to define a body for the function. If you are familiar with other programming languages' interfaces, you can see a protocol as essentially the same thing.

Therefore, the protocol above says that anything that implements it must have an empty? function, however, it is up to the implementer as to how the function responds. 

Now, let’s learn how to add a few implementations to the protocol we defined.

Implementing a Protocol

Now that we have defined a protocol, we need to instruct it on how to handle the different inputs that it might get. So, we will build on the above example. let's implement the blank protocol for lists, maps, and strings, and it will show if the things passed is blank or not. Check the code below.

#Defining the protocol
defprotocol Blank do
   def blank?(data)
end

#Implementing the protocol for lists
defimpl Blank, for: List do
   def blank?([]), do: true
   def blank?(_), do: false
end

#Implementing the protocol for strings
defimpl Blank, for: BitString do
   def blank?(""), do: true
   def blank?(_), do: false
end

#Implementing the protocol for maps
defimpl Blank, for: Map do
   def blank?(map), do: map_size(map) == 0
end

IO.puts(Blank.blank? [])
IO.puts(Blank.blank? [:true, "Hello"])
IO.puts(Blank.blank? "")
IO.puts(Blank.blank? "Hi")

Note that you can implement your Protocol for as many or as few types as you want, that is whatever makes sense for the usage of your Protocol can be implemented. The above code is a basic case of the use of protocols. 

The output is:

true
false
true
false

It is important to note that if you use this for any types other than those you defined the protocol for, an error will be produced.