Skip to content

Defaults to optional arguments suppress warning 68 in hard-to-predict ways #12175

@ncik-roberts

Description

@ncik-roberts

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions