This is a follow up on my previous post on Ad-hoc Polymorphism. I highly recommend reading the previous post first. In this post we will refactor the same code to use defprotocol
construct. At the end of this post you will notice that using defprotocol
results in better encapsulation and fewer lines of code.
defprotocol
is a means to achieving ad-hoc polymorphism. Ad-hoc polymorphism in simple terms is a technique of varying behaviour based on their types. Complex states can be modeled in Elixir using the defstruct
construct. States defined using defstruct
can be used as types for achieving ad-hoc polymorphism.
Lets use defprotocol
to define a protocol (aka behavior) that we want to vary based on structs.
defprotocol ConnectionHandler do
def handle(con)
end
defimpl
let's us implement different behaviors for protocols defined using the defprotocol
construct, as shown below.
defmodule ConnectionHandler.FirstConnectionHandler do
defstruct con: nil
defimpl ConnectionHandler, for: ConnectionHandler.FirstConnectionHandler do
def handle(%ConnectionHandler.FirstConnectionHandler{con: con}) do
"First"
end
end
end
defmodule ConnectionHandler.SecondConnectionHandler do
defstruct con: nil
defimpl ConnectionHandler, for: ConnectionHandler.SecondConnectionHandler do
def handle(%ConnectionHandler.SecondConnectionHandler{con: con}) do
"Second"
end
end
end
Below shown test demonstrates how everything glues together. If you have read the previous post, you might notice that no change has been made to the test.
defmodule Blaze.Test do
use ExUnit.Case
defprotocol ConnectionHandler do
def handle(con)
end
defmodule ConnectionHandler.FirstConnectionHandler do
defstruct con: nil
defimpl ConnectionHandler, for: ConnectionHandler.FirstConnectionHandler do
def handle(%ConnectionHandler.FirstConnectionHandler{con: con}) do
"First"
end
end
end
defmodule ConnectionHandler.SecondConnectionHandler do
defstruct con: nil
defimpl ConnectionHandler, for: ConnectionHandler.SecondConnectionHandler do
def handle(%ConnectionHandler.SecondConnectionHandler{con: con}) do
"Second"
end
end
end
test "demonstration of `defprotocol`" do
alias ConnectionHandler.FirstConnectionHandler
alias ConnectionHandler.SecondConnectionHandler
assert ConnectionHandler.handle(%FirstConnectionHandler{con: []}) == "First"
assert ConnectionHandler.handle(%SecondConnectionHandler{con: []}) == "Second"
end
end
This post demonstrates that in Elixir using defprotocol
for adhoc-polymorphism leads to fewer lines of code and better encapsulation.
Top comments (0)