variant
A discriminated union: a named set of constructors, each carrying zero or more payload types. A value of the type is one constructor and its payloads.
variant Angle {
DMS(int32, int32, int32);
Radians(float64);
}Constructors
Each constructor is a name, an optional payload list, and a semicolon. The names are scoped to the
variant and reached through it, as Angle.Radians.
- A variant declares at least one constructor.
- Constructor names are unique within the variant. Arity is not part of the name, so
Firm;andFirm(string);collide. - A constructor may carry no payload. The list may be omitted or written empty, and
Firm;andFirm();declare the same nullary constructor. - A payload type may be the variant being declared, so a route is a variant that holds the rest of itself.
messagemay precedevariant, marking the type as something components send each other in a protocol.
variant TrackQuality {
Firm;
Tentative();
Dropped(string);
}
variant Route {
Stop(string);
Leg(string, Route);
}
message variant SensorReport {
Bearing(float32);
Silent;
}Values
A constructor with payloads is applied the way a function is called. A nullary constructor is used bare or with empty parens, and both forms give the same value.
- The application supplies exactly as many arguments as the constructor has payload types.
- Each argument must be assignable to its payload type.
- Payloads have no names, so matching is what reads them back out.
variant TrackQuality {
Firm;
Dropped(string);
}
const firm: TrackQuality = TrackQuality.Firm;
const also_firm: TrackQuality = TrackQuality.Firm();
firm == also_firm // => true
TrackQuality.Dropped("lost") // => TrackQuality.Dropped("lost")Matching
A pattern names a constructor and binds its payloads positionally. Each binding is in scope in that arm's body.
- A pattern binds exactly as many sub-patterns as the constructor has payload types.
- A bare
TrackQuality.Firmpattern binds none, which is correct for a nullary constructor only.
variant Angle {
DMS(int32, int32, int32);
Radians(float64);
}
function whole_degrees(a: Angle) -> int32 = match (a) {
Angle.DMS(deg, min, sec) => deg;
Angle.Radians(rad) => 0;
};
whole_degrees(Angle.DMS(45, 30, 0)) // => 45
whole_degrees(Angle.Radians(1.57)) // => 0Errors
A variant with no constructors
variant TrackQuality {} // error: empty-variant, expectedTwo constructors with one name
The payload list is not part of the name, so a second Dropped collides whatever it carries.
variant TrackQuality {
Dropped(string);
Dropped(uint32); // error: duplicate-variant-constructor
}Applying a constructor with the wrong number of arguments
A bare reference counts as zero arguments, so it is an argument short of a constructor that carries a payload.
variant TrackQuality {
Firm;
Dropped(string);
}
const A: TrackQuality = TrackQuality.Dropped; // error: call-arg-count
const B: TrackQuality = TrackQuality.Firm("lost"); // error: call-arg-countA payload argument of the wrong type
variant TrackQuality {
Dropped(string);
}
const A: TrackQuality = TrackQuality.Dropped(7); // error: call-arg-typeA pattern that binds the wrong number of payloads
variant TrackQuality {
Firm;
Dropped(string);
}
function label(q: TrackQuality) -> string = match (q) {
TrackQuality.Dropped(reason, code) => reason; // error: incompatible-pattern
_ => "firm";
};