Interfaces in Erlang

In Erlang, we can define behaviors which are similar to interfaces in other languages. We’ll use this concept to demonstrate how to work with geometric shapes.

-module(geometry).
-export([measure/1]).

% Define the behavior (interface) for geometric shapes
-callback area() -> float().
-callback perim() -> float().

% Implement the behavior for rectangles
-module(rect).
-behavior(geometry).
-export([new/2, area/1, perim/1]).

new(Width, Height) ->
    #{width => Width, height => Height}.

area(#{width := W, height := H}) ->
    W * H.

perim(#{width := W, height := H}) ->
    2 * W + 2 * H.

% Implement the behavior for circles
-module(circle).
-behavior(geometry).
-export([new/1, area/1, perim/1]).

new(Radius) ->
    #{radius => Radius}.

area(#{radius := R}) ->
    math:pi() * R * R.

perim(#{radius := R}) ->
    2 * math:pi() * R.

% Generic measure function that works with any geometry
measure(Shape) ->
    io:format("~p~n", [Shape]),
    io:format("~p~n", [Shape:area()]),
    io:format("~p~n", [Shape:perim()]).

% Main function to demonstrate usage
main() ->
    R = rect:new(3, 4),
    C = circle:new(5),
    measure(R),
    measure(C).

In this Erlang code:

  1. We define a behavior geometry with two callback functions: area/0 and perim/0.

  2. We implement this behavior for rect and circle modules. Each module has its own implementation of area/1 and perim/1.

  3. The measure/1 function takes any shape that implements the geometry behavior and calls its area/1 and perim/1 functions.

  4. In the main/0 function, we create instances of rect and circle, and then call measure/1 on each of them.

To run this program, you would typically compile each module separately and then run the main/0 function in the Erlang shell:

1> c(geometry).
2> c(rect).
3> c(circle).
4> geometry:main().
#{width => 3,height => 4}
12.0
14.0
#{radius => 5}
78.53981633974483
31.41592653589793
ok

This demonstrates how Erlang can use behaviors (similar to interfaces) to work with different types in a generic way. The measure/1 function can operate on any shape that implements the geometry behavior, showcasing polymorphism in Erlang.