Ideas: more attributes to tweak the record layout

+1 for the bindings to tagged unions
I’m using rust + wasm-bindgen + rescript at work and would benefit a lot from this, currently we need to have lots of wrapper functions.

2 Likes

I agree!
+1 for the bindings to tagged unions

1 Like

Can anyone give me an example how bindings of tagged unions would look like or how are useful? I read the linked issue and don’t get it

OK, I re-read the issue and seems that the proposal is to being able to bind to some things that behave like tagged unions on the JS side and let those just be normal tagged unions ing rescript rather than just records. Right?

What are the advantages of this? Seems confusing for no clear benefit

You are encouraged to create a separate topic to discuss the feature you proposed.
Let’s keep the discussions on this topic, otherwise we will get distracted.

Another possibility is introduce a strict attribute, e.g,

@strict
type record = {
   field1 : string,
   field2 : int
}

For records tagged with strict attribute, the compiler will not do anything special with it, this is useful for bindings.
For other records, we can add a command line flag, e.g, --minify-record, so that in production builds, the size gets smaller

3 Likes

I think both way are great.

In the case of a project with low or no interop with js/ts, a command line flag for minify and array with the @strict attribute seems perfect.

However, in the case with high interop, we want most of the record to be “normal”, so adding attribute for @minify and @array seems a better way to go.

Definetly something I want to see in rescript ! :slight_smile:

What do you mean by normal? Normality is a very subjective term. Do you mean always have the same fields?

Regarding @minify:

I’m curious what the use cases for this might be? If code is intended for a browser, then sending the generated code through a minifier library would achieve optimal results, and if the code is intended to run on a server then I’m not sure there is a need for minification?

Regarding @array:

I’m assuming the output would be an array of the values in the same order they appear in the record?

On one hand, this is conceptually similar to tuples, but you can refer to the tuple elements by name which may be nice. E.g. field1 refers to the first element of the “tuple”, and field2 is the second element of the “tuple”.

If I am understanding the proposal correctly then for regular records the order of the fields does not matter, but with the @array decorator the order of the fields does matter. I would have a concern here that it is very simple to change the field order in ReScript and without any warning interop with existing JS may suddenly break. Comparing with tuples we don’t have this same fragility because order is intrinsic to the data structure. Overall @array feels like it may introduce fragile interop behaviour.

As a side note, something like “named tuples” might serve a more intuitive behaviour, such as type record1 = (~field1=string, ~field2=int) and tuple fields could be specified in any order such as let myrecord = (~field2=0, ~field1="x") but the generated code always strictly follows the order of the type definition.

Regarding @strict:

I’m not sure how best to express the concept here, but decorators that have an unambiguous impact on compiler behaviour seems like good language design. Having decorators that may or may not do something depending on command line flags feels like a complicated/confusing developer experience. And if the initial use case is for minification, then I wonder if there is any need. Why not just use a minification library?

Thanks for sharing your thoughts @Hongbo

6 Likes

This is my feeling too

I mean, in an interop context, it’s preferable to have a regular record by default instead of an array representation. By “normal” I mean “regular”, though it was clear… ^^’

That’s why it’s optional and probably should not be used if you need interop on the given structure.

I kinda thought the same. The attribute name mangling will also make the code way harder to read / troubleshoot during runtime. Feels like a lot of extra concepts and I just can’t see any particular use-case where I’d want that builtin minification system over already existing minification infrastructure & gzipping.

Still not sure where this feature would be useful, and I see a lot of footguns whenever a developer adds or reorders a record field.

Another rule to keep in mind. If a library uses it, it’s hard to spot.

For me, the most interesting feature mentioned in this thread would be the (off-topic) zero-cost tagged-union transform.

6 Likes

IIRC, most (all?) JS minifiers don’t minify object field names. I assume this is because doing so would break a lot of JS code that relies on specific object keys.

I’m happy to be proven wrong, though. Or maybe this is a non-issue if you use gzip?

1 Like

I think they only possible compression is through gzip, which should be very efficient in this case.
However the ability to strip out undefined fields is not to save bandwidth, is to ensure correct interaction with Javascript code that doesn’t check the field value and only checks if the field exists at all (even if is undefined). This is more common than you may think.

I also want to re ask what is the use case of the array, other than introducing confusion when you see an array on the generates JS code where it used to be a record.

I think this the best design. Minification would be useful, but the @minify attribute seems like it would create confusion.

How about a more explicit attribute, like @nominify? “Strict” can have ambiguous meanings.

Both terser and closure compiler can do this.
I know rescript can do that safer/better but i don’t think saving some bytes would be that important.
tree shaking/removing dead code and general minifcations done by js minifiers combined with compression in asset delivery is enough for everyone.

5 Likes

I didn’t think Terser did, but then I looked it up and you’re correct. However, it does have this warning:

Note: THIS WILL BREAK YOUR CODE. A good rule of thumb is not to use this unless you know exactly what you’re doing and how this works and read this section until the end.

Considering that ReScript records aren’t as complex as most JS objects, I wonder if ReScript is safer to use with this option?

You get the point.

For most minifiers, their property mangling is incorrect and in-efficient, while our type based minifier is correct and more efficient.

The correctness is guaranteed by the type system.

Why it is more efficient?

Since it is type based, so you can map both field1 and field2 to a, if they are of different types. I proposed this since this is something we can do far better than the existing alternatives