Skip to content

Conversation

@zth
Copy link
Member

@zth zth commented Oct 27, 2025

Something to discuss post v12

Add support for providing "catch all" variant constructors to tagged variants, to allow capturing all non-literal discriminator cases of a variant. This lets you write a variant that can enumerate a few known discriminators, and "catch" the rest at runtime in a single catch-all constructor, for those runtime values you haven't statically enumerated.

Rationale

Consider a common interop type with a numeric discriminant where only a few literal values are special, and everything else should go to “Other”:

@tag("status") type response = | @as(202) Ok202({}) | @as(200) Ok200({data: JSON.t}) | @as(int) Other({status: int, body: string}) let decode = (x: response) => switch x { | Ok202(_) => Console.log("202 received") | Ok200({data}) => Console.log2("200 received with data:", data) | Other({status, body}) => Console.log3("Other received with status:", status, "and body:", body) // All other status codes end up here }

Before this feature, there was no elegant way to express “everything else that’s a number” for a tagged variant. You either had to hand‑write a decoder that inspects x.status and constructs a variant by enumerating all literal cases yourself, or attempt exhaustive matches that still couldn’t represent unknown future values. Hand‑written decoding is tedious, error‑prone, and typically forces you to duplicate the discriminant logic outside the type just to avoid runtime match failures.

With a primitive catch‑all annotation like @as(int|float|string), the type itself states the intent. The compiler generates literal‑first checks over the discriminant field and only then falls back to a single primitive “catch all” branch. This captures the real‑world use case (you only care about a few literals; everything else of that primitive kind is one case), avoids bespoke decoders, and stays sound even when a particular match expression doesn’t enumerate all literal members.

@cristianoc
Copy link
Collaborator

Tried to paste the example in a prompt and ask for what JS this produces.
The result was confusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

3 participants