module Unions {
// UNION BASICS
// a union type consists of other types. a union value could be any of those types
// but a given value will only be one of those types at a time.
//
// the values in a union are overlayed in memory. the union contains an additional
// field which references the the type of the current value.
//
// union types are structural types, meaning two union types with the same set
// of types are considered the same type.
//
// the simplest form of a union type is just a set of types separated by |
fn test1() {
let x : string | int = 1; // x is int
x = "hello"; // x is string
// using is or typeof with a union will result in the type of
// the current value, not the type of the union itself.
print(typeof(x) == ::string); // prints true
print(x is string); // prints true
// to obtain the value of a union, cast to its type
if (x is string) { // if the union contains a string
let s = x::string; // cast union to string
print(s); // prints hello
}
// match can also be used with unions
// see match for more information
match (x) {
@x : string => print(x); // prints "hello"
@x : int => print(x); // does not match since x is a string
}
}
// NAMED UNIONS
// unions can also be defined using union, which allows the above syntax
// but also additional options (see below). Named unions define a new
// type.
union CssDimension {
int | string
}
// LABELED UNIONS
// using union allows labeled types. A labeled type is defined within the union
// and it's type is scoped to the union type.
// define a union with three labeled types
union Axis {
x : int;
y : int;
z : int;
}
fn test2() {
let a : Axis; // variable a is of type Axis
a = Axis(z : 2); // constructs an Axis.z value
a = Axis(y : 2); // constructs an Axis.y value
a = Axis(x : 1); // constructs an Axis.x value
// to check if a union u contains a label l, use u.l?
// to obtain the value of a label, use u.l
if (a.x?) {
print(a.x); // prints 2
}
// match can also be used with labeled unions
// see match for more information
match (a) {
Axis(x : @x) => print(x); // prints 2
Axis(y : @y) => print(y); // does not match
Axis(z : @z) => print(z); // does not match
}
// match can also be used to match against
// the label type, see match for more information
match (a) {
Axis.x => print("x"); // prints x
Axis.y => print("y"); // does not match
Axis.z => print("z"); // does not match
}
}
// DEFINING STRUCTS IN UNIONS
// As a shortcut, structures can be defined directly within a union
// This is equivalent to defining the structure separately
// For example, the following
//
// struct Line {
// length: double;
// }
//
// struct Circle {
// radius : double;
// }
//
// union Shape {
// Line | Circle
// }
// could have been written
union Shape {
Line{length : double}
Circle{radius : double}
}
// INCLUDING UNIONS
// To include the members of a union in other union, use ... before the union type being included.
typedef SignedInt = i8 | i16 | i32 | i64;
typedef UnsignedInt = u8 | u16 | u32 | u64;
typedef SignedOrUnsignedInt = ...SignedInt | ...UnsignedInt;
// EXTENSIBLE UNIONS
// by default, union only accept values from the set of types they define. to allow other
// types to be defined separately from the union, use ... at the end of the union.
// define a Url union with two types
union Url {
// define two types
Https{host : string; path : string = ""; query : string = ""; fragment : string = ""}
Http{host : string; path : string = ""; query : string = ""; fragment : string = ""}
... // allow other types to be added
}
// add a type to the Url union
union ...Url {
File{path : string}
}
// add another type to the Uri union
union ...Url {
MailTo{email: string; body : string; cc: string}
}
fn test4() {
let url : Url;
url = Http("https", "google.com");
url = Https("https", "google.com", "/", "", "");
url = MailTo("someone@example.com");
}
}