DEV Community

Pankaj Sharma
Pankaj Sharma

Posted on

2

Ad-hoc Polymorphism In Elixir Using defprotocol

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.

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more