To expand on yaramin’s answer:
The Js.Dict api is mutable. Calling Js.Dict.set on a dict will mutate the underlying js object.
Therefore if Js.Dict.empty were a value (just an empty js object), every occurrence would reference exactly the same object.
To circumvent this empty is a function returning a new empty Dict.
Js.Dict is mutable and for Js.Dict.set there is a note at the end of the function description.
I need to add () for functions expecting unit, like for Js.Dict.empty(). This is a little confusing given the fact that in many other cases, especially when piping functions, the parenthesis are not needed: number->Belt.Int.toString / number->Js.Int.toString.
We should probably put in the Js.Dict module description that this is a mutable representation of a JS object…
That is an inconsistency we sadly have to live with right now.
Rule of thumb: You always need to provide parenthesis for a function call, but you may need () for pipe calls, depending on the arguments.
It makes sense when you think about how -> is being interpreted:
Is essentially transformed into
If you’d do "string"->Js.String2.toUpperCase() it would turn into Js.String2.toUpperCase("test", ()) which is wrong from an arity perspective.
We can’t special case toUpperCase(), because ReScript is a curried language with possible optional labeled arguments.
For example, whenever your last argument would be an optional label, you’d need to provide a final () to tell the compiler that we are applying the function.