rescript-compiler
rescript-compiler copied to clipboard
Proposal to provide [@bs.objFn]
This proposal is to provide a [@bs.objFn]. This would work similar to [@@bs.obj] function
https://bucklescript.github.io/docs/en/object-2#function
The benefits of bs.obj over other techniques is that:
- You can have an object with many optional values and only provide the entries you need to the function, rather than type
Nonemany times like you would have to do with records ofJs.t - The transpiled code is clean and not verbose, it's a straightforward object which discludes the fields that you never included, which is important for some libraries that rely heavily on this kind of stuff and want to maintain small bundle sizes
The drawback to using it is that it's not ergonomic. It works okish for configs, but not that great for the JS FFI or for writing a library that heavily relies on optional values while trying to maintain a small bundle size. This proposal is for syntax like this:
external someFn: string -> (?foo: string -> ?bar: int -> ?baz -> bool -> unit [@bs.objFn]) -> t = "someFn" [@@bs.module "some-module"]
let x = someFn "hi" ~bar:123 ~baz:true ()
which compiles to:
var x = someFn("hi", { bar: 123, baz: true})
To do something similar with [@@bs.obj] would require something like someFn "hi" (someFnObj ~bar:123 ~baz:true ()) which is very verbose
To map to functions that take an object for the arguments, I define a series of records (most encapsulated in their own module) that map to different combinations of argument keys which I might want to use.
I then define separate externals per record type mapping to the same JS function. Similar effect, and imo a lot more type safe.
I can see where this would be handy if you had 20 different combinations you wanted to bind to, though.
@TheSpyder That only works for things that require a small number of variations. For example, with bs-declaredom that would literally create millions of entries just for one element: https://github.com/Risto-Stevcev/bs-declaredom/blob/master/src/html/Html_Nodes.mli#L27-L98
That would make things much worse and the current api for bs-declaredom is already much larger than I would like it to be, because labelled args end up compiling to really verbose javascript which makes the library pretty unusable because of the large bundle size. Using [@@bs.obj] can drastically reduce the bundle size but the ergonomics are horrible
Yes, which is why I said
I can see where this would be handy if you had 20 different combinations you wanted to bind to, though.
However I think your proposal in #3870 might be better 🤔
From the implementation point of view, this is more approachable than proposal #3870
this would simplify so many bindings! A lot of bindings have been significantly improved thanks to latest changes in runtime representations (records, variants, etc), this is one of the last use cases where current bindings feel a bit awkward.
I'd love to see something like this as well! Lots of recent JS library APIs lean on taking a single object as a parameter.
This would be great for writing ergonomic bindings.
Looks like we are be getting something in the next release that helps in this area, #5253. It might solve the use case completely - hard to tell just from the final PR in a series of changes.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I think we can close this issue thanks to optional fields in records (#5423)