Roles for Belt,Js, and Pervasives in ReScript

I am not a big fan of using open. Is that lots of typing compared with below?

module L = Belt.List
let {map, filter , every}  = module (Belt.List)

If Belt is affordable, that is the only lib you need, it is actually more performant than JS, just a bit more intrusive than JS, so Js may fit a niche use case when you want to convert existing Js code into ReScript

2 Likes

I used to use belt as it is (not opening via compiler flag) but i ened up creating lots of aliases and opens at start of expressions / modules.

1 Like

This is what I was talking about in my point. Most of Js is runtime free, but there are also parts of Belt that are optimized and necessary for writing clean JS, like Belt.Array.getUnsafe mentioned in another post.

Js and Belt are very linked, to the point where it is confusing to beginners to the language (where I count myself in). I’m sure if you are used to the distinction and the names it feels like it is not a problem, but it is a big unnecessary detail.

For example, like knowing that for working with arrays here is the array type globally available, there is Js.Array2, and there is Js.Vector (??? just learnt about this), and there is Belt.Array, all with different functions, some that are just like the Js functions, some that are mutable utilities, some that treat the array as immutable. This is a lot of incidental complexity that is fully self-created, and if you are cleaning up, it is the time to address it.

Think about who you are targeting, is it converting JS users? If that is an important audience, think about what they do. For example with Array:

  • There is one array type
    • Solution: Unify all the array modules to make it easy in the autocomplete and docs
  • I call functions on it without even knowing the module type
    • Solution: Well it is not possible to do this, but reducing the api surface to one name xs->Array.length is the shortest we can do.
      Anything longer, Js.Array2., Belt.Array, Js.Vector all lose in length to `` which is the prefix JS developers have to use to call an array function.
  • To know if an Array function is mutable or immutable, as a Js dev I rely on the docs mainly
    • Solution: Great, we have great docs. We can also split the functions in the docs by mutable / immutable, and on each function clearly specify if the array is mutated in place. We also have the return types which are a good indicator of the mutability. Highlight this.

Anyway just an example, and my perspective. You can always get used to the idiosincrasies of each language but if you are cleaning up with breaking changes, it may be worth rethinking the design in a more holistic way. Maybe it is just my Elm experience showing here, the standard library is a pleasure to learn, very well designed and documented.

6 Likes

Yes that would be a great idea!

I don’t know if it’s worth the trouble. Adding a library dependency is trivial in ReScript. You might just go ahead and remove the Stdlib library altogether once you are confident you cover everything. Anyone who wants it back can install it separately.

2 Likes

Maintain the legacy stdlib is non-trivial work, there are lots of C shims to support in the compiler, it can not be maintained by 3rd party.

As we discussed, the retirement plan for ocaml stdlib would be that we first have a flag to allow users to explicitly opt-out; later opt-out by default and final removal

1 Like

Reading all that, I think that a -stdlib-future flag would be great.

I’m currently experimenting a bit on what would make a newcomer experience easier by only exposing a subset of Pervasives, and I came down to the following module: rescript-js/ReScriptJs__Pervasives.res at main · bloodyowl/rescript-js · GitHub

I also think that, apart from the internals like Obj.camlEqual, CamlInternalLazy, internal int32 and so on, this flag could only make it so that only the following modules would be exposed:

  • Lazy
  • Int64 (while BigInt still has some light support, but that could be implemented user-land)

What do you think?

3 Likes

Can you go to the pervasives module and mark functions not needed as deprecated, or we put it in a separate module, e.g Belt.Float for lots of float operations in Pervasives?

-stdlib-future is to ensure that none of the legacy stdlib will be exposed,
we can provide more polished APIs in Belt.Lazy/Belt.Int64 etc.

Contributions are welcome

1 Like

I’m in favour of this, although the OCaml standard library doesn’t impact my project too much. Some context may be useful for the discussion.

The project I’m working on has a stdlib replacement combining elements of Belt and Js along with some custom sprinkles and renaming methods to match existing libraries in our main TypeScript codebase. It may even be open source by the end of the year.

The only files that don’t have open Tiny at the top are the ones the stdlib depends on. If/when we’re able to switch to pinned packages in our monorepo we’ll consider something like "bsc-flags": [ "-open Tiny" ] or similar in the individual package bsconfig.json files.

2 Likes

Relevant GH issue: Add BigInt primitive number type · Issue #4677 · rescript-lang/rescript-compiler · GitHub

When is getting rid of default ocaml library planned? I was already confused by it when I used some arrays.

See the Roadmap

In ReScript version 11 which will be next year.

Thanks. Can it be deactivated already with some compiler flag?

Not directly, but there is a bsconfig setting to exchange the built-in std lib with an external one:

"external-stdlib" : "@rescript/std"

It is probably possible to exchange the @rescript/std with your own minimal one.

The easiest way to not use the OCaml standard library is to open Belt in each module. Belt will shadow a lot of the OCaml modules like Array. (Although it won’t replace all of them. You probably need to use Js.String2 instead of the built in String module, for example.)

You can configure rescript to automatically open Belt for every file by putting this in your bsconfig.json:

{
  "bsc-flags" : ["-open Belt"]
}
2 Likes

Yep, that is indeed a solution.
I guess that, after all, no runtime is just a “selling point” which, while technically possible, is not realistic

3 Likes