"JS-friendly" representation of (normal) variants

Since ReScript 8.2, polymorphic variants are compiled to a JS-friendly representation, see https://rescript-lang.org/blog/string-literal-types-in-reason. By “JS-friendly”, I mean that values can be easily understood in log output or in the debugger.


Js.log(#messageReceived("Hello, ReScript"))

results in

{ NAME: 'messageReceived', VAL: 'Hello, ReScript' }

Compare this with

type event =
  | Connected
  | Disconnected
  | MessageReceived(string)

Js.log(MessageReceived("Hello, ReScript"))

which results in

{ _0: 'Hello, ReScript' }

Reading this output or inspecting values in the debugger, it is unclear at first glance what these values mean (especially if there are more cases in the variant than in my simple example).

Therefore, I was asking myself if it would it be possible to change the encoding of normal variants to match the encoding of polymorphic variants.

I found an experimental PR changing the variant representation here https://github.com/rescript-lang/rescript-compiler/pull/3801, but this was never merged.

What are your thoughts - would this be feasible?

1 Like

Hi, thanks for bringing this up.

In the short/mid term, we don’t have plans to change the data type encoding, so the ABI should be quite stable for a while.

  • With regard to your proposal, the prototype is nice, but the compiler has some implicit invariants for how normal algebraic data type is encoded, for example, the tag has to be continuous, so it would be more work than you thought.

  • It is not always win, it is a trade off, our current encoding is optimal for runtime performance and code size

  • The debug mode should give you sensible output for normal ADT

  • We may consider allow user to customize the encoding using attributes in the future.

  • Using structural variant for simple data types like event here makes sense too, so you can stick to structural variant for such use cases. Another good thing about structural variant is that even package a depends on the package b's structural type, package a does not need depend on package b, so you can cut off the dependencies using structural types for protocol.


Hi Bob,

Thanks a lot for the explanation. I already feared that this might not be a trivial change.

Glad to hear that you are considering customizations of the encoding in the longer-term future though.

E.g., it would also be nice if we could use type instead of NAME for the representation of polymorphic variants for easier JS interop (many JS libs expect Redux-style action objects with the type of the action encoded in a type prop).