Interfaces in Elixir

In Elixir, we don’t have interfaces in the same way as Go, but we can achieve similar behavior using protocols. Here’s how we can implement the geometry example:

defprotocol Geometry do
  def area(shape)
  def perim(shape)
end

defmodule Rect do
  defstruct width: 0, height: 0

  defimpl Geometry, for: Rect do
    def area(rect), do: rect.width * rect.height
    def perim(rect), do: 2 * rect.width + 2 * rect.height
  end
end

defmodule Circle do
  defstruct radius: 0

  defimpl Geometry, for: Circle do
    def area(circle), do: :math.pi() * circle.radius * circle.radius
    def perim(circle), do: 2 * :math.pi() * circle.radius
  end
end

defmodule Shapes do
  def measure(shape) do
    IO.inspect(shape)
    IO.puts(Geometry.area(shape))
    IO.puts(Geometry.perim(shape))
  end
end

# In the main function
rect = %Rect{width: 3, height: 4}
circle = %Circle{radius: 5}

Shapes.measure(rect)
Shapes.measure(circle)

In this Elixir code:

  1. We define a Geometry protocol with area and perim functions.

  2. We create Rect and Circle structs and implement the Geometry protocol for each.

  3. The measure function in the Shapes module takes any shape that implements the Geometry protocol.

  4. In the main part of the script, we create instances of Rect and Circle and pass them to the measure function.

To run this program, save it in a file (e.g., shapes.exs) and use the elixir command:

$ elixir shapes.exs
%Rect{width: 3, height: 4}
12
14
%Circle{radius: 5}
78.53981633974483
31.41592653589793

Elixir’s protocols provide a way to achieve polymorphism, similar to interfaces in other languages. They allow us to define a set of functions that can be implemented by different types, enabling us to write more generic and reusable code.