Struct Embedding in Karel

Java supports composition of classes, which is similar to struct embedding in other languages. This allows for a more seamless composition of types.

import java.util.function.Supplier;

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;
    }
}

class Container {
    private Base base;
    private String str;

    public Container(int num, String str) {
        this.base = new Base(num);
        this.str = str;
    }

    // Delegate method to access base's num
    public int getNum() {
        return base.getNum();
    }

    // Delegate method to access base's describe
    public String describe() {
        return base.describe();
    }

    public String getStr() {
        return str;
    }
}

interface Describer {
    String describe();
}

public class StructComposition {
    public static void main(String[] args) {
        // When creating objects, we initialize the composition explicitly
        Container co = new Container(1, "some name");

        // We can access the base's fields through delegated methods
        System.out.printf("co={num: %d, str: %s}%n", co.getNum(), co.getStr());

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

        // Composition can be used to implement interfaces
        Describer d = co::describe;
        System.out.println("describer: " + d.describe());
    }
}

In Java, we use composition to achieve a similar effect to struct embedding. The Container class contains an instance of Base and delegates certain methods to it.

When creating objects with composition, we initialize the composed class explicitly in the constructor.

We can access the base’s fields through delegated methods in Container, such as co.getNum().

Since Container composes Base, we can delegate the methods of Base to become methods of Container. Here we invoke a method that was delegated from Base directly on co.

Composition can be used to implement interfaces. Here we see that a Container now implements the Describer interface because it delegates to Base.

To run the program:

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

This example demonstrates how Java uses composition to achieve a similar effect to struct embedding, allowing for flexible and reusable code structures.