Struct Embedding in Mercury

Java supports composition of types through inheritance and interfaces. This allows for a more seamless integration of different types and behaviors.

import java.util.StringJoiner;

class Base {
    private int num;

    public Base(int num) {
        this.num = num;
    }

    public String describe() {
        return String.format("base with num=%d", num);
    }

    public int getNum() {
        return num;
    }
}

// A Container extends Base. This is similar to embedding in other languages.
class Container extends Base {
    private String str;

    public Container(int num, String str) {
        super(num);
        this.str = str;
    }

    public String getStr() {
        return str;
    }
}

// Define an interface for objects that can describe themselves
interface Describer {
    String describe();
}

public class StructEmbedding {
    public static void main(String[] args) {
        // When creating objects, we initialize the base class and the additional fields
        Container co = new Container(1, "some name");

        // We can access the base's fields directly on co, e.g. co.getNum()
        System.out.printf("co={num: %d, str: %s}\n", co.getNum(), co.getStr());

        // We can also access the base methods directly
        System.out.println("describe: " + co.describe());

        // Since Container extends Base, it automatically implements the Describer interface
        Describer d = co;
        System.out.println("describer: " + d.describe());
    }
}

To run this program:

$ javac StructEmbedding.java
$ java StructEmbedding
co={num: 1, str: some name}
describe: base with num=1
describer: base with num=1

In this Java example, we use inheritance to achieve a similar effect to struct embedding. The Container class extends the Base class, which allows it to inherit the describe() method and the num field.

We also define a Describer interface, which is implicitly implemented by both Base and Container classes because they have a describe() method.

The main differences from the original example are:

  1. Java uses class inheritance instead of struct embedding.
  2. We need to use getter methods to access fields from the base class.
  3. The syntax for creating objects is different, using the new keyword and a constructor.
  4. Java interfaces are explicitly declared, while in the original they were implicit.

Despite these differences, the core concept of composition and method inheritance is preserved in this Java implementation.