Struct Embedding in Erlang

Erlang supports pattern matching and function clauses to express composition of types. This is somewhat different from struct embedding in other languages, but it allows for a similar kind of abstraction and code reuse.

-module(struct_embedding).
-export([main/0]).

% Define a record for base
-record(base, {num}).

% Function to describe base
describe_base(#base{num = Num}) ->
    io_lib:format("base with num=~p", [Num]).

% Define a record for container, which includes base
-record(container, {base, str}).

main() ->
    % Create a container with base
    Co = #container{
        base = #base{num = 1},
        str = "some name"
    },

    % We can access the base's fields directly on Co
    io:format("co={num: ~p, str: ~p}~n", [Co#container.base#base.num, Co#container.str]),

    % Alternatively, we can spell out the full path using the record names
    io:format("also num: ~p~n", [Co#container.base#base.num]),

    % We can call the describe function for the base part of the container
    io:format("describe: ~s~n", [describe_base(Co#container.base)]),

    % In Erlang, we don't have interfaces, but we can achieve similar behavior with function calls
    describe(Co).

% Function to describe any record that has a base field
describe(#container{base = Base}) ->
    io:format("describer: ~s~n", [describe_base(Base)]).

When creating records with literals in Erlang, we initialize the embedded record explicitly. Here, we create a container record that includes a base record.

We can access the base’s fields on Co using the syntax Co#container.base#base.num.

In Erlang, we don’t have methods associated with records, but we can define functions that operate on these records. The describe_base/1 function serves a similar purpose to the describe() method in the original Go code.

Erlang doesn’t have interfaces, but we can achieve similar behavior by defining functions that pattern match on records. The describe/1 function at the end demonstrates this concept.

To run the program:

$ erlc struct_embedding.erl
$ erl -noshell -s struct_embedding main -s init stop
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

This example demonstrates how Erlang can achieve similar compositional patterns to struct embedding in Go, albeit with different syntax and concepts.