DEV Community

Pankaj Sharma
Pankaj Sharma

Posted on

1

Ad-hoc Polymorphism in Elixir

Ad-hoc polymorphism is a kind of polymorphism that uses types and polymorphic functions (aka function overloading) to change the function behavior depending on the types of its arguments.

While behaviour and defprotocol are preferred options for achieving polymorphism in Elixir, there is also one more option, probably more simplistic. Ad-hoc polymorphism can be achieved in Elixir using a combination of plain structs, function overloading, pattern matching and destructuring.

First step is to wrap the state, that needs polymorphic behavior in a struct, as shown below.

  defmodule ConnectionHandler.FirstConnectionHandler do
    defstruct con: nil
  end

  defmodule ConnectionHandler.SecondConnectionHandler do
    defstruct con: nil
  end

Then create a module which will house the overloaded functions, that would pattern match over the structs that we just created.

  defmodule ConnectionHandler do
    alias ConnectionHandler.FirstConnectionHandler
    alias ConnectionHandler.SecondConnectionHandler

    def handle(%FirstConnectionHandler{con: con}) do
      "First"
    end

    def handle(%SecondConnectionHandler{con: con}) do
      "Second"
    end
  end

Below shown simple test case demonstrates how it all glues together.

defmodule ConnectionHandler.Test do
  use ExUnit.Case

  defmodule ConnectionHandler.FirstConnectionHandler do
    defstruct con: nil
  end

  defmodule ConnectionHandler.SecondConnectionHandler do
    defstruct con: nil
  end

  defmodule ConnectionHandler do
    alias ConnectionHandler.FirstConnectionHandler
    alias ConnectionHandler.SecondConnectionHandler

    def handle(%FirstConnectionHandler{con: con}) do
      "First"
    end

    def handle(%SecondConnectionHandler{con: con}) do
      "Second"
    end
  end

  test "ad-hoc polymorphism demonstration" do
    alias ConnectionHandler.FirstConnectionHandler
    alias ConnectionHandler.SecondConnectionHandler

    assert ConnectionHandler.handle(%FirstConnectionHandler{con: []}) == "First"
    assert ConnectionHandler.handle(%SecondConnectionHandler{con: []}) == "Second"
  end
end

While this is a way of achieving polymorphism in Elixir, one might want to consider more idiomatic approach of using defprotocol.

Update: Part 2 of this series demonstrates how using defprotocol retults in better encapsulation and fewer lines of code.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

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