Compiler option to use the NAME representation for Variants

I would love to have an option in the compiler, to make it translate variant types the it does for polymorphic variant types. This is, instead of casting the value with an JS object {TAG: int, _0: <payload>, ...}; use a {NAME: string, _0: ...}.

Is it possible or too-difficult? Can it be put in the roadmap? Is there a planned feature that would make this possible or better?

2 Likes

What usecase do you have for this feature?

Explaining that would help motivate why this should be included as a feature.

The main use case would be debugging while developing. For instance, I have these types:

type rec vtype =
  | TBooleanType
  | TIntegerType(
      {
        "min_value": option<int>,
        "max_value": option<int>,
        "min_included": bool,
        "max_included": bool,
      },
    )
  | TObjectType({"shape": Dict.t<vtype>})
  | TOptionalType({"type": vtype})
  | TBinaryType({"expected_kinds": array<kind>})
  | ... more here, not shown ...

type partialized<'t> = option<'t>
type rec partial =
  | PartialBooleanValue(partialized<bool>, vtype)
  | PartialOptionalValue(option<partial>, vtype)
  | PartialObjectValue(array<(string, partial)>, vtype)
  | PartialBinaryValue(partialized<{"id": string}>, vtype)
  | ... more here, not shown ...

While, developing a function default that takes a vtype and returns partial, I did a clerical mistake:

let rec default = (var: vtype): partial =>
  switch var {
  | TBooleanType => PartialBooleanValue(None, var)
  | TBinaryType(_) => PartialBooleanValue(None, var)  // <-- wrong value

It type checks, but is incorrect to return a PartialBooleanValue for a TBinaryType. So, I put some Js.Console.log here and there to find the issue and having a TAG instead of a NAME didn’t help much.

Maybe there are better debugging approaches or safer typing strategies for this specific problem. Nevertheless, I think having something like this can really help in some situations.

Gotcha, as far as I know you can look at the generated javascript for where the variant is used to see its value.

Here as an example 1 corresponds to Provider in rescript.

Not exactly what you want, but it could be helpful, you can also give them numbers that you want using @as(321) so that they are easier to recognize Generate Converters & Helpers | ReScript Language Manual

I’m not involved at all with the compiler, so not sure if that is something the core team would consider

The -bs-g compiler flag enables the debug mode that shows the variant constructor names when printing. Maybe this flag can help you?

You can enable this by adding "bsc-flags": ["-bs-g"] to your bsconfig.json

3 Likes

Gotcha, as far as I know you can look at the generated javascript for where the variant is used to see its value.

Hi @JaasooS,

I know the compiler does this; but unfortunately rescript is just a part of our bigger app and we need other tools (we use esbuild) to merge all into one big .js file; moreover, the logs (Js.Console.log) are not always close to the point where the value was created. In my example, it took me some time to go from the place where the issue manifested, back to the function default.

The -bs-g compiler flag enables the debug mode that shows the variant constructor names when printing. Maybe this flag can help you?

Hi @mxthevs, I will try this.

I tried this @as thing, but it doesn’t work for non-polymorphic variants. The playground shows this:

Try genType:

This will translate the TAG properties into the constructor names at runtime.

There has been some discussion around improving the ability to interop with variant constructors in the compiler, but for the moment genType is the best practice.