-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Defaults to optional arguments suppress warning 68 in hard-to-predict ways #12175
Description
Note
This issue will be fixed by an implementation for ocaml/RFCs#32, which I'm working on. That RFC fixes this issue by specifying the evaluation order of optional argument defaults / pattern matches on mutable state, which removes the need for warning 68. In the meantime, I'm writing this to log and track a perhaps-surprising behavior.
Bug
Warning 68 notes when matching on mutable state (e.g. a mutable record field) prevents a function from being uncurried:
# let f1 { contents } x = contents + x;;
Warning 68 [match-on-mutable-state-prevent-uncurry]: This pattern depends on mutable state.
It prevents the remaining arguments from being uncurried, which will cause additional closure allocations.
val f1 : int ref -> int -> int = <fun>But placing an optional argument with a default value immediately before the pattern suppresses that warning:
# let f2 ?(foo = print_endline "evaluated") { contents } x = contents + x;;
val f2 : ?foo:unit -> int ref -> int -> int = <fun>
# f2 (ref 0);;
evaluated
- : int -> int = <fun>This behavior is arguably ok if you think of the optional argument default, and not the mutable field pattern, as being the reason that uncurrying is interrupted. (So, perhaps it's confusing to mention the mutable field pattern in the warning.) But, the current behavior could be undesirable for a few reasons:
- The warning raises in an unpredictable set of circumstances
- The warning doesn't even catch all cases where removing a pattern match on a mutable field would allow the uncurrying translation to kick in. For example, if we remove the mutable field pattern from the above example, the uncurrying still happens such that the evaluation of the default argument is delayed until the function is fully applied:
# let f3 ?(foo = print_endline "evaluated") x y = !x + y;;;
val f3 : ?foo:unit -> int ref -> int -> int = <fun>
# f3 (ref 1);;
# f3 (ref 1) 2;;
evaluated
- : int = 3