superstruct

This module provides a single type, SuperStruct.

Members

Functions

pick
auto pick(size_t index, T values)

Wrap one of several values in a SuperStruct.

Structs

SuperStruct
struct SuperStruct(SubTypes...)

A Variant which exposes members that are common across all SubTypes.

Examples

Two disparate structs ... they can't be used interchangeably, right?

import std.math, std.algorithm;

struct Square {
  float size;
  float area() { return size * size; }
}

struct Circle {
  float r;
  float area() { return r * r * PI; }
}

// Or can they?
alias Shape = SuperStruct!(Square, Circle);

// look! polymorphism!
Shape sqr = Square(2);
Shape cir = Circle(4);
Shape[] shapes = [ sqr, cir ];

// call functions that are shared between the source types!
assert(shapes.map!(x => x.area).sum.approxEqual(2 * 2 + 4 * 4 * PI));

Want to access fields of the underlying types? Not a problem! Are some of them properties? Not a problem!

struct Square {
  int top, left, width, height;
}

struct Circle {
  int radius;
  int x, y;

  auto top() { return y - radius; }
  auto top(int val) { return y = val + radius; }
}

alias Shape = SuperStruct!(Square, Circle);

// if a Shape is a Circle, `top` forwards to Circle's top property
Shape someShape = Circle(4, 0, 0);
someShape.top = 6;
assert(someShape.top == 6);

// if a Shape is a Square, `top` forwards to Squares's top field
someShape = Square(0, 0, 4, 4);
someShape.top = 6;
assert(someShape.top == 6);

// Square.left is hidden, as Circle has no such member
static assert(!is(typeof(someShape.left)));

SuperStruct could be used, for example, for a generic container type:

import std.range, std.algorithm, std.container;

alias Container(T) = SuperStruct!(SList!T, Array!T);

Container!int slist = SList!int();

// We can call any members that are common among containers
slist.insert([1,2,3,4]);
assert(slist.front == 1);

// opSlice is supported on all the subtypes, but each returns a different type
// Container.opSlice will return a SuperStruct of these types
auto slice = slist[];     // [1,2,3,4]
assert(slice.front == 1);
slice.popFront();         // [2,3,4]
assert(slice.front == 2);

// as slice is a SuperStruct of range types, it still works as a range
slist.insert(slice); // [2,3,4] ~ [1,2,3,4]
assert(slist[].equal([2,3,4,1,2,3,4]));

Meta

Authors

Ryan Roden-Corrent (rcorre)