Struct Embedding in D Programming Language

import std.stdio;

struct Base {
    int num;

    string describe() {
        import std.format : format;
        return format("base with num=%d", num);
    }
}

struct Container {
    Base base;
    string str;
}

void main() {
    // When creating structs with literals, we have to
    // initialize the embedding explicitly; here the
    // embedded type serves as the field name.
    auto co = Container(Base(1), "some name");

    // We can access the base's fields directly on `co`,
    // e.g. `co.base.num`.
    writefln("co={num: %d, str: %s}", co.base.num, co.str);

    // Alternatively, we can spell out the full path using
    // the embedded type name.
    writeln("also num: ", co.base.num);

    // Since `Container` embeds `Base`, we can invoke the method
    // that was defined in `Base` through the `Container` instance.
    writeln("describe: ", co.base.describe());

    // D doesn't have a direct equivalent to Go's interface embedding,
    // but we can achieve similar functionality using templates or
    // interfaces with abstract methods.
    interface Describer {
        string describe();
    }

    // We can implement the Describer interface for Container
    // by forwarding the call to the embedded Base struct.
    class DescribableContainer : Describer {
        Container container;

        this(Container container) {
            this.container = container;
        }

        string describe() {
            return container.base.describe();
        }
    }

    Describer d = new DescribableContainer(co);
    writeln("describer: ", d.describe());
}

D supports struct composition, which is similar to Go’s struct embedding. However, there are some differences in how it’s implemented and used.

In D, we define the Base and Container structs. The Container struct contains a Base instance as a member, which is similar to embedding in Go.

D doesn’t have a direct equivalent to Go’s interface embedding, but we can achieve similar functionality using interfaces and inheritance. In this example, we define a Describer interface and implement it for Container using a wrapper class DescribableContainer.

To run the program, save it as struct_composition.d and use the D compiler:

$ dmd struct_composition.d
$ ./struct_composition
co={num: 1, str: some name}
also num: 1
describe: base with num=1
describer: base with num=1

This example demonstrates struct composition in D, which is conceptually similar to struct embedding in other languages. It shows how to access fields and methods of the embedded struct, and how to implement interfaces using composition.