Struct Embedding in Nim

Nim supports embedding of objects to express a more seamless composition of types. This is similar to inheritance but with some distinct characteristics.

import strformat

type
  Base = object
    num: int

proc describe(b: Base): string =
  fmt"base with num={b.num}"

# A `Container` embeds a `Base`. In Nim, this is done through inheritance.
type
  Container = object of Base
    str: string

proc main() =
  # When creating objects, we initialize the embedded type's fields
  # along with the Container's fields.
  var co = Container(num: 1, str: "some name")

  # We can access the base's fields directly on `co`, e.g. `co.num`.
  echo fmt"co={{num: {co.num}, str: {co.str}}}"

  # We can also access the fields using the full path.
  echo "also num: ", co.Base.num

  # Since `Container` inherits from `Base`, the methods of
  # `Base` also become methods of `Container`. Here
  # we invoke a method that was inherited from `Base`
  # directly on `co`.
  echo "describe: ", co.describe()

  # Defining an interface-like concept in Nim
  type
    Describer = concept x
      x.describe() is string

  # Inheritance in Nim allows `Container` to be used
  # where a `Describer` is expected, similar to interface
  # implementation in other languages.
  var d: Describer = co
  echo "describer: ", d.describe()

main()

To run the program, save it as struct_embedding.nim and use the Nim compiler:

$ nim c -r struct_embedding.nim
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

In this Nim example, we use inheritance to achieve a similar effect to Go’s struct embedding. The Container type inherits from Base, which allows it to access Base’s fields and methods directly.

Nim uses the object of syntax to denote inheritance, which is analogous to embedding in this context. The describe method is automatically available to Container objects due to this inheritance.

The concept of interfaces in Go is mimicked in Nim using the concept keyword, which allows for duck-typing-like behavior. This enables us to use Container where a Describer is expected, similar to how Go’s implicit interface implementation works.

While the syntax and some specifics differ, this Nim code captures the essence of the original Go example, demonstrating type composition and method inheritance.