Nicer way of defining an array

Hey there,

I’ve been trying to get into Rescript and I have a few questions I have about Arrays, for which I couldn’t find answers online.

First of, I couldn’t find an equivalent of coming from js/ts. Let’s say I have a function getWords() => array<string>. What is the Rescript equivalent of the following js bit:

let myArray = ["Start", ...getWords(), "End"];

Right now the best solution I have come up with is:

open Js.Array2
let words = ["Start"]
words->pushMany(getWords())->ignore
words->push("End")->ignore
  1. Is there a more succint/elegant way of doing this? It’s very verbose compared to the js equivalent.
  2. Related to 1. , is it common to have to use ->ignore? According to this comment: What to do to ignore unused returned values - #2 by yawaramin it shouldn’t be. So if there is no more succint way of writing this bit, is there at least a way to avoid ->ignore?
  3. According to this comment Belt.Array, Js.Array, Js.Array2 - #5 by chenglou (which is really concerning to read as a newcomer…); Js.Array2 shouldn’t be used in the first place? I see there is also Belt.Array, is it actually recommended to blindly use this one instead of Js.Array2 if we don’t care about the runtime overhead? If yes, it looks like there is no equivalent in Belt.Array to Js.Array2.pushMany, is there something else I should be using that I missed?

Thanks in advance!

let words = ["Start"]
  -> Js.Array2.concat(getWords ())
  -> Js.Array2.concat(["End"])

For ignore, in FP languages you’re meant to write everything as an expression. Think of it more as “is a” than a “then this then than.” Example

  • words is an array with “Start”. Then push getWords. Then push “End”

vs

  • words is an array of getWords with Start and End surrounding it

It’s a small but important way of distinguishing coding styles

3 Likes

If we try the given example in ReScript directly, we get this error message:

Arrays can't use the `...` spread currently. Please use `concat` or other Array helpers.

If we look up concat, Belt.Array.concat seems like a good option. In ReScript we can even do operator overloading if we’re careful not to override the global default:

let getWords = () => ["hello", "hi"]

let myArray = {
  let \"+" = Belt.Array.concat
  ["Start"] + getWords() + ["End"]
}
7 Likes

concat is what I missed then, thank you two! I’m looking forward to being able to use the spread operator on arrays.

And wow, this is a very curious example. I wonder how much it’s actually used in real world cases? It looks a bit magical to me.

Custom operators are used a lot in languages like OCaml, depending on the team. Overdoing them can lead to unreadable code though, so it’s probably a good idea to only introduce them for frequently used operations, so that:

  1. The existence of the operator is well justified.
  2. All the team has a great chance to learn it and not be puzzled by it.

In ReScript specifically, custom operators are encouraged less than in some other languages, because the core team doesn’t really endorse them, and because a better support of them by the parser would require some work by that same team. But they’re here for legacy reasons, and some devs coming from OCaml/ReasonML swear by them.

P.S.

It looks a bit magical to me.

It’s not really magical in the sense that something is happening that is not obvious from your immediate code (as far as you know what the operator does). In a lot of functional languages, an expression with an infix operator is just a syntax sugar for a binary function call, so 1 + 2 is just sugar for (+)(1, 2).

3 Likes