Docs / Language Manual / Extensible Variant
Edit

Extensible Variant

Variant types are usually constrained to a fixed set of constructors. There may be very rare cases where you still want to be able to add constructors to a variant type (even after its initial type declaration). For this, we offer extensible variant types.

Definition and Usage

ReScriptJS Output
 
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.

ReScriptJS Output
 
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.