TaggedAlgebraic

Implements a generic algebraic type using an enum to identify the stored type.

This struct takes a union or struct declaration as an input and builds an algebraic data type from its fields, using an automatically generated Kind enumeration to identify which field of the union is currently used. Multiple fields with the same value are supported.

All operators and methods are transparently forwarded to the contained value. The caller has to make sure that the contained value supports the requested operation. Failure to do so will result in an assertion failure.

The return value of forwarded operations is determined as follows:

  • If the type can be uniquely determined, it is used as the return value
  • If there are multiple possible return values and all of them match the unique types defined in the TaggedAlgebraic, a TaggedAlgebraic is returned.
  • If there are multiple return values and none of them is a Variant, an Algebraic of the set of possible return types is returned.
  • If any of the possible operations returns a Variant, this is used as the return value.

Constructors

this
this(TaggedAlgebraic other)
Undocumented in source.

Members

Aliases

Kind
alias Kind = UnionType.Kind

A type enum that identifies the type of value currently stored.

Type
deprecated alias Type = Kind

Compatibility alias

Union
deprecated alias Union = U

Alias of the type used for defining the possible storage types/kinds.

UnionType
alias UnionType = TaggedUnion!U

The underlying tagged union type

typeID
deprecated alias typeID = kind
Undocumented in source.

Functions

opAssign
void opAssign(TaggedAlgebraic other)
Undocumented in source. Be warned that the author may not have intended to support it.
opBinary
auto ref opBinary(T other)

Enables the use of binary operators with the stored value.

opBinaryRight
auto ref opBinaryRight(T other)

Enables the use of binary operators with the stored value.

opCall
auto ref opCall(ARGS args)

Enables call syntax operations on the stored value.

opCast
T opCast()

Enables conversion or extraction of the stored value.

opCmp
auto ref opCmp(T other)

Enables relational comparisons with the stored value.

opEquals
auto ref opEquals(T other)

Enables equality comparison with the stored value.

opEquals
bool opEquals(TaggedAlgebraic other)
Undocumented in source. Be warned that the author may not have intended to support it.
opIndex
auto ref opIndex(ARGS args)

Enables indexing operations on the stored value.

opIndexAssign
auto ref opIndexAssign(ARGS args)

Enables index assignments on the stored value.

opOpAssign
auto ref opOpAssign(T other)

Enables operator assignments on the stored value.

opUnary
auto ref opUnary()

Enables the use of unary operators with the stored value.

toHash
size_t toHash()
Undocumented in source. Be warned that the author may not have intended to support it.
toString
string toString()

Uses cast(string)/to!string to return a string representation of the enclosed value.

Properties

kind
Kind kind [@property getter]

The type ID of the currently stored value.

Templates

opDispatch
template opDispatch(string name)

Enables the access to methods and propeties/fields of the stored value.

Examples

1 import funkwerk.stdx.data.json.taggedalgebraic.taggedalgebraic;
2 
3 struct Foo {
4 	string name;
5 	void bar() @safe {}
6 }
7 
8 union Base {
9 	int i;
10 	string str;
11 	Foo foo;
12 }
13 
14 alias Tagged = TaggedAlgebraic!Base;
15 
16 // Instantiate
17 Tagged taggedInt = 5;
18 Tagged taggedString = "Hello";
19 Tagged taggedFoo = Foo();
20 Tagged taggedAny = taggedInt;
21 taggedAny = taggedString;
22 taggedAny = taggedFoo;
23 
24 // Check type: Tagged.Kind is an enum
25 assert(taggedInt.kind == Tagged.Kind.i);
26 assert(taggedString.kind == Tagged.Kind.str);
27 assert(taggedFoo.kind == Tagged.Kind.foo);
28 assert(taggedAny.kind == Tagged.Kind.foo);
29 
30 // In most cases, can simply use as-is
31 auto num = 4 + taggedInt;
32 auto msg = taggedString ~ " World!";
33 taggedFoo.bar();
34 if (taggedAny.kind == Tagged.Kind.foo) // Make sure to check type first!
35 	taggedAny.bar();
36 //taggedString.bar(); // AssertError: Not a Foo!
37 
38 // Convert back by casting
39 auto i   = cast(int)    taggedInt;
40 auto str = cast(string) taggedString;
41 auto foo = cast(Foo)    taggedFoo;
42 if (taggedAny.kind == Tagged.Kind.foo) // Make sure to check type first!
43 	auto foo2 = cast(Foo) taggedAny;
44 //cast(Foo) taggedString; // AssertError!
45 
46 // Kind is an enum, so final switch is supported:
47 final switch (taggedAny.kind) {
48 	case Tagged.Kind.i:
49 		// It's "int i"
50 		break;
51 
52 	case Tagged.Kind.str:
53 		// It's "string str"
54 		break;
55 
56 	case Tagged.Kind.foo:
57 		// It's "Foo foo"
58 		break;
59 }

Operators and methods of the contained type can be used transparently.

static struct S {
	int v;
	int test() { return v / 2; }
}

static union Test {
	typeof(null) null_;
	int integer;
	string text;
	string[string] dictionary;
	S custom;
}

alias TA = TaggedAlgebraic!Test;

TA ta;
assert(ta.kind == TA.Kind.null_);

ta = 12;
assert(ta.kind == TA.Kind.integer);
assert(ta == 12);
assert(cast(int)ta == 12);
assert(cast(long)ta == 12);
assert(cast(short)ta == 12);

ta += 12;
assert(ta == 24);
assert(ta - 10 == 14);

ta = ["foo" : "bar"];
assert(ta.kind == TA.Kind.dictionary);
assert(ta["foo"] == "bar");

ta["foo"] = "baz";
assert(ta["foo"] == "baz");

ta = S(8);
assert(ta.test() == 4);

Multiple fields are allowed to have the same type, in which case the type ID enum is used to disambiguate.

static union Test {
	typeof(null) null_;
	int count;
	int difference;
}

alias TA = TaggedAlgebraic!Test;

TA ta = TA(12, TA.Kind.count);
assert(ta.kind == TA.Kind.count);
assert(ta == 12);

ta = null;
assert(ta.kind == TA.Kind.null_);

Meta