Is unit as a last argument an anti-pattern?


#1

Dr. Axel Rauschmayer suggests, that if your function has non-erasable optional parameters, you should add one more parameter of type unit:

let add = (~x=0, ~y=0, ()) => x + y;

Incidentally, Reason compiler seems to suggest the same.

Meanwhile, RWO talks about non-erasable parameters but says nothing about the above pattern. Is it just an oversight on Mr. Minsky’s part, is that addition not deemed important, or is that practice actually frowned upon? I mean, it does feel kinda weird to put optional parameters last if you plan to partially apply your function, but maybe I’m missing something.


#2

The convention which I have seen is to put the unit parameter whenever you have non-erasable optional parameters, like Rauschmayer suggests.

That being said, if your function does have non-erasable parameters, you can “manually erase” them by doing the following.

let add = (~x=0, ~y=0) => x + y;
/* let add: (~x: int=?, ~y: int=?) => int = <fun>; */
let addWithDefaultX = add(~x=?None);
/* let addWithDefaultX: (~y: int=?) => int = <fun>; */
let addWithDefaultY = add(~y=?None);
/* let addWithDefaultY: (~x: int=?) => int = <fun>; */
let addWithDefaultXY = add(~x=?None, ~y=?None);
/* let addWithDefaultXY: int = 0; */

#3

Hey, I think that may come in handy if you have some unfortunate JS libs. Thanks!

But other than that, I tend to think that you shouldn’t author functions like that at all. Especially if you expect that the last parameter is going to be supplied through a pipe.

But then, I don’t know, maybe the unit parameter is useful when you have a function that takes a gazillion options, like some kind of factory, maybe? But it’s like having a record with a lot of optional parameters: a nightmare to grok (and test for) all the possible variations. Almost back to the jungle of no types at all :scream:


#4

There’s some discussion about how future Reason syntax might remove this requirement here: https://github.com/facebook/reason/issues/2181