The right Option module (and the rigth getWithDefault)


Obviously, we have Js.Option and Belt.Option modules that do nearly the same, but not quite: some misses this, some that. To make it worse, they have an almost identical function, getWithDefault, that is 'a option -> 'a -> 'a, properly t-first in Belt.Option but 'a option -> 'a -> 'a in Js.Option, which doesn’t make it too fast-pipe-friendly.

Why two modules at all? Is one of them going to be deprecated? If not, when to choose one over another?

let v = Some("value");

/* With classical pipe */
let _ = v |> Js.Option.getWithDefault("default");

/* With fast pipe */
let _ = v->Belt.Option.getWithDefault("default");


Yeah, that part I understand, thanks! You could also go v->Js.Option.getWithDefault("default", _). I just find it confusing: if t-first is the Belt way, why is Js.Option ignoring that convention?

Also, Js.Option and Belt.Option provide different sets of functions, so t-first/t-last is not the only difference.


Currently I choose Belt if it provides the necessary functionality. When it doesn’t drop down to Js.

why is Js.Option ignoring that convention?

Js.Option dates back to when the OCaml pipe operator |> was the only pipe operator and it pipes to the right most argument - i.e. Js.Option.getWithDefault was optimized for |> (and continues to work with it).

Belt on the other hand was designed according to the more recently adopted BuckleScript conventions.

Piping to the last argument makes sense in a language where functions are curried. For example giving Js.Option.getWithDefault its first argument creates a function where the default is already set, ready to be used with any number of option values.

That convenience was sacrificed for the new conventions. To compensate there is an expanded partial application notation:

/* let newFunc = Js.Option.getWithDefault(defaultValue); */
let newFunc = Belt.Option.getWithDefault(_, defaultValue);

but that may be deprecated in the future - so it’s back to

/* same argument order as Js.Option.getWithDefault(default, value) */
let makeNewFunc = (default, value) =>
  Belt.Option.getWithDefault(value, default);
let newFunc = makeNewFunc(defaultValue);

For the gory details see


Ah, the infamous t-first discussion. I choose too belive the Reason authors know what they’re doing until proven otherwise :). Even if they’re fighting an uphill battle, because even the members of the community that don’t actively oppose to t-first style, still tend to port Elm/OCaml/Haskell solutions that tend to favor traditional pipes.



Partial application is the heavy lifter. Curried functions are just icing on the cake. But apparently lots of people just can’t live without icing on their cake.


Well, curried function make for consistent style between |> and lower order callbacks, but given that those callbacks can be composed from other functions, or created in place, it doesn’t seem such a huge loss.