Compiler question: Why can't I mix optional and labelled arguments without getting an erasure warning?

I like labels as I find they help me read and make sense of function signatures. Unfortunately trying to mix optional arguments with labelled ones throws this compiler warning: Common Error Messages · OCaml Tutorials

I can define a function like this and use it either with all arguments + labels or without any labels:

let test ?(opt = 1) ~req = opt + req;;
Line 1, characters 11-18:
Warning 16 [unerasable-optional-argument]: this optional argument cannot be erased.
val test : ?opt:int -> req:int -> int = <fun>

test 1;;
Line 1, characters 0-4:
Warning 6 [labels-omitted]: label req was omitted in the application of this function.
Line 1, characters 0-4:
Warning 6 [labels-omitted]: label req was omitted in the application of this function.
- : int = 2

test ~opt:2 ~req:1;;
- : int = 3

Unfortunately the most useful use-case doesn’t work:

test ~req:1;;
- : ?opt:int -> int = <fun>

I know I can work around this problem by sprinkling () on all my functions but it feels like code smell to me.

Is this limitation in OCaml a historic mishap or is there something in how the compiler works that makes this an undecidable problem?

It’s because of the interaction between automatic currying and optional arguments. The question becomes, if an optional argument is not provided, is it because the programmer wants the function to be partially applied or not? Using a positional argument in the call removes the ambiguity.

1 Like