Struct Embedding in Dart

Dart supports composition of classes through mixins and inheritance, which can be used to achieve a similar effect to struct embedding in other languages. This example demonstrates how to use these features to create a more seamless composition of types.

import 'dart:core';

class Base {
  int num;

  Base(this.num);

  String describe() {
    return 'base with num=$num';
  }
}

// A `Container` uses a mixin to include `Base`
class Container with Base {
  String str;

  Container(int num, this.str) : super(num);
}

// Define an interface
abstract class Describer {
  String describe();
}

void main() {
  // When creating instances, we initialize the mixin properties
  var co = Container(1, 'some name');

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

  // We can also access the mixin's methods directly
  print('describe: ${co.describe()}');

  // Mixins and inheritance can be used to implement interfaces
  Describer d = co;
  print('describer: ${d.describe()}');
}

To run the program, save it as class_composition.dart and use the dart command:

$ dart run class_composition.dart
co={num: 1, str: some name}
describe: base with num=1
describer: base with num=1

In this Dart example:

  1. We define a Base class with a num property and a describe() method.

  2. Instead of struct embedding, we use a mixin to include Base in Container. This allows Container to inherit the properties and methods of Base.

  3. We create an instance of Container, initializing both its own property (str) and the mixin’s property (num).

  4. We can access the mixin’s properties and methods directly on the Container instance.

  5. We define an interface Describer with a describe() method. Because Container includes the Base mixin which has this method, it automatically implements this interface.

  6. We demonstrate that a Container instance can be assigned to a Describer variable, showing that it indeed implements the interface.

This approach in Dart achieves a similar effect to struct embedding, allowing for composition of types and implicit interface implementation. However, it’s important to note that Dart’s approach using mixins and inheritance has some differences in behavior and limitations compared to Go’s struct embedding.