Struct Embedding in Elixir

In Elixir, we can achieve similar functionality to struct embedding using composition and delegate. Here’s how we can translate the concept:

defmodule Base do
  defstruct [:num]

  def describe(%{num: num}) do
    "base with num=#{num}"
  end
end

defmodule Container do
  defstruct [:base, :str]

  defdelegate describe, to: :base
end

defimpl String.Chars, for: Container do
  def to_string(%{base: %{num: num}, str: str}) do
    "co={num: #{num}, str: #{str}}"
  end
end

defmodule Main do
  def run do
    co = %Container{
      base: %Base{num: 1},
      str: "some name"
    }

    # We can access the base's fields directly on co
    IO.puts("#{co}")

    # Alternatively, we can spell out the full path
    IO.puts("also num: #{co.base.num}")

    # We can call the describe function which is delegated to Base
    IO.puts("describe: #{Container.describe(co)}")

    # In Elixir, we don't need to explicitly declare interfaces
    # The protocol system provides similar functionality
    IO.puts("describer: #{Container.describe(co)}")
  end
end

Main.run()

In this Elixir version:

  1. We define a Base struct with a num field and a describe function.

  2. We define a Container struct that includes a base field (which will be a Base struct) and a str field.

  3. We use defdelegate to delegate the describe function to the base field. This is similar to embedding in Go, allowing Container to use Base’s describe function.

  4. We implement the String.Chars protocol for Container to allow easy printing of its contents.

  5. In the Main module, we create a Container instance and demonstrate how to access fields and call the delegated describe function.

  6. Elixir doesn’t have interfaces in the same way as Go, but its protocol system serves a similar purpose. In this case, any struct that implements a describe function could be used interchangeably where a “describer” is expected.

When you run this program, you’ll get output similar to:

co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

This example demonstrates how Elixir can achieve functionality similar to Go’s struct embedding through composition and delegation.