diff --git a/data/sidebar_manual_latest.json b/data/sidebar_manual_latest.json index 3d42984c2..9b516a776 100644 --- a/data/sidebar_manual_latest.json +++ b/data/sidebar_manual_latest.json @@ -33,6 +33,9 @@ "unboxed", "reserved-keywords" ], + "Advanced Features": [ + "extensible-variant" + ], "JavaScript Interop": [ "embed-raw-javascript", "shared-data-types", diff --git a/pages/docs/manual/latest/extensible-variant.mdx b/pages/docs/manual/latest/extensible-variant.mdx new file mode 100644 index 000000000..0569bd6b0 --- /dev/null +++ b/pages/docs/manual/latest/extensible-variant.mdx @@ -0,0 +1,75 @@ +--- +title: "Extensible Variant" +description: "Extensible Variants in ReScript" +canonical: "/docs/manual/latest/extensible-variant" +--- + +# 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 + + + +```res example +type t = .. + +type t += Other + +type t += + | Point(float, float) + | Line(float, float, float, float) +``` +```js +var Caml_exceptions = require("./stdlib/caml_exceptions.js"); + +var Other = Caml_exceptions.create("Playground.Other"); + +var Point = Caml_exceptions.create("Playground.Point"); + +var Line = Caml_exceptions.create("Playground.Line"); +``` + + + +The `..` in the type declaration above defines an extensible variant `type t`. The `+=` operator is then used to add constructors to the given type. + +**Note:** Don't forget the leading `type` keyword when using the `+=` operator! + +## 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. + + + + + +```res +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") + } +``` +```js +function print(v) { + if (v.RE_EXN_ID === Point) { + console.log("Point", [v._1, v._2]); + } else if (v.RE_EXN_ID === Line) { + console.log("Line", [v._1, v._2, v._3, v._4]); + } else { + console.log("Other"); + } +} +``` + + + +## Tips & Tricks + +**Fun fact:** In ReScript, [exceptions](./exception) are actually extensible variants under the hood, so `exception UserError(string)` is equivalent to `type exn += UserError(string)`. It's one of the very few use-case where extensible variants make sense. + +We usually recommend sticking with common [variants](./variant) as much as possible to reap the benefits of exhaustive pattern matching. \ No newline at end of file