Belt.Array, Js.Array, Js.Array2

Hello,

I see there are 2 Array modules:

  • Belt.Array
  • Js.Array
  • Js.Array2

While Js.Array, Js.Array2 seem to have the same API.

Why do we need 2 modules to handle the Array?

I see similar also with List.

Also, the String is defined in Js.String and not in Belt

As a beginner I would say it’s pretty confusing.

Which one do I use?
Are they interchangeable?

2 Likes

The Js module mostly contains Reason bindings to standard JavaScript APIs like console.log, or the JavaScript String, Date, and Promise classes.

Belt is the standard lib, and right now it mostly implements something that cannot be done with Js: Option, Result and some collections. They do plan to implement Belt.Script, but maybe most of the Js will still remain, because those are zero-cost bindings, while the Belt modules are not.

As for Array vs Array2, those have different argument order. Array2, being data-first, is more future-friendly, but I doubt the name stays :slight_smile:

2 Likes

@hoichi, thank you so much for the explanation.

It seems like there is a lot of work in progress on ReScript.

There is, but both the type system and the compiler are rock-solid, and I’d argue it matters more than the standard library in the long run.

EDIT: Sorry, I’ve forgotten the link to the argument order explanation.

1 Like

The Js.Array2 module was supposed to be hidden but unfortunately our documentation tool exposed it and people started using it. But yes, it’s the recommended version over Js.Array and Pervasives.Array.

Belt.Array has a bigger runtime and isn’t idiomatic JS. Slightly different use-cases. This should be cleaned up. Sorry about that…

3 Likes

Adding another one in here - the Array. methods. So I think there are 4 ways…

let aaa = [1, 2, 3]->Array.map(i => i * 2, _)
let bbb = [1, 2, 3]->Js.Array2.map(i => i * 2)
let ccc = [1, 2, 3]->Js.Array.map(i => i * 2, _)
let ddd = [1, 2, 3]->Belt.Array.map(i => i * 2)

I’m confused how the first one - Array.map - even works. What “module” is that coming from? How does that relate to the others? I have a similar question about when I use the words Some and None - seems like these should be in Js.Option or Belt.Option but I don’t see them there.

Hi @jmagaram , if you don’t have some strict requirement, you are recommended to stick with Belt. This is indeed confusing and acknowledged

Ok. Note this somewhat contradicts information on API | ReScript API (rescript-lang.org) which steers people to Js.Array2. I just wrote some unit tests that demonstrate one danger of Js.Array2. In functional programming you get used to comparing objects by their contents not by reference. Js.Array2.includes does the usual javascript thing - reference comparison - which is unexpected in a functional environment. I notice Belt.Array does not have an includes function probably for this reason.

type person = {first: string, last: string}
describe("arrays", () => {
  test("Js.Array2.includes uses structural equality", () => {
    let a = {first: "justin", last: "smith"}
    let b = {first: "justin", last: "smith"}
    [a]->Js.Array2.includes(b)->expect->toEqual(true) // fails
  })
  test("Belt.Array.includes uses structural equality", () => {
    let a = {first: "justin", last: "smith"}
    let b = {first: "justin", last: "smith"}
    [a]->Belt.Array.some(i => i == b)->expect->toEqual(true)
  })
})

1 Like