Extensible Variant
Variant types are usually constraint to a fixed set of constructors that are defined in its type declaration. There may be very rare cases where you still want to be able to add constructors to a variant type (e.g. in different places of your program). For this, we offer extensible variant types.
Definition and Usage
type t = ..
type t += Other
type t +=
| Point(float, float)
| Line(float, float, float, float)
The ..
in the type declaration above defines an extensible variant type t
. The +=
operator is then used to add constructors to the given type.
Pattern Matching Caveats
Extensible variants are open-ended, so the compiler will not be able to exhaustively pattern match all available cases. You will always need to provide a default _
case for every switch
expression.
let print = v =>
switch v {
| Point(x, y) => Js.log2("Point", (x, y))
| Line(ax, ay, bx, by) => Js.log2("Line", (ax, ay, bx, by))
| Other
| _ => Js.log("Other")
}
Tips & Tricks
Fun fact: In ReScript, exceptions are actually implemented as extensible variants under the hood, so exception UserError(string)
is equivalent to type exn += UserError(string)
. It's probably one of the few use-cases were extensible variants make sense. We usually recommend sticking with common variants as much as possible to reap the benefits of exhaustive pattern matching.