DEV Community

loading...

Discussion on: Emulating TypeScript union types with ReasonML

Collapse
citizen428 profile image
Michael Kohl • Edited

polyvariants will warn about typos though

If you misspell it in the match expression inside icons, polymorphic variants can't know that that's not what you meant, so you won't find the typo until exercising the code, worst case at runtime.

This is opposed to the following code, that won't compile with the error The variant constructor ArrowDonw can't be found.

type t =
  | ArrowDown
  | ArrowLeft;

let icons =
  fun
  | ArrowDonw => {"label": "Down Arrow"}
  | ArrowLeft => {"label": "Left Arrow"};

A similar example is given in Real World OCaml, which points out that this can be particularly problematic when combining polymophic variants with catch-all cases. I.e. if you had a final clause like

| _ => {"label": "Unknown button"}

it could take quite a while until you find the typo in the match.

There are certainly times when polymorphic variants are the only reasonable choice (your example is a good one), but I think one needs to be aware of potential pitfalls.

Thread Thread
yawaramin profile image
Yawar Amin Author

Try out a typo in the icons definition in my code sample, you'll see the error at compile time 🙂 In fact you even hinted as to why: because I didn't use a catch-all case. That's exactly what causes the polymorphic variant type to be inferred as 'less than these cases', as I mentioned before. Definitely agree though that these are subtleties that need to be understood for proper usage. Real World OCaml is a good resource to learn about those, for sure.

Thread Thread
citizen428 profile image
Michael Kohl • Edited

Try out a typo in the icons definition in my code sample, you'll see the error at compile time 🙂

But that's because you're exercising icons via iconLabel inside the JS.log function. If you remove that it will compile just fine:

Playground

Generally, you wouldn't have a JS.log statement in a library, so if you happen to call icons("arrowDown"); during runtime (i.e. by taking it from a keypress event) you'd get an error about it not being part of [<arrowDonw | arrowLeft ] then, not at compile time.

This wouldn't happen with a regular union type:

Playground 2

That's really all I tried to say 😀

Thread Thread
yawaramin profile image
Yawar Amin Author

Hmm, I still don't see how that could happen though 🤔 at some point in the code we would call icons(something) where something is a polymorphic variant tag. At that point the typechecker would step in to point out if you called it with icons(`arrowDown) which is not handled by the icons function (assuming the typo in its definition). You wouldn't be calling the icons function with a string, it's not stringly typed.

Thread Thread
citizen428 profile image
Michael Kohl

Yup, sorry, the string was a mistake, should have been `arrowDown.

I guess I was thinking too much about a hypothetical case that is either extremely unlikely or impossible, so thanks for taking the time and patiently explaining 😀