Description
I propose to emit a warning when forgotten parentheses turn a DU deconstruction into a function definition that shadows the DU case.
This would remove a common case of puzzlement for developers.
type T = Case1 of int
let t = Case1 42
let Case1 x = t // shouldn't this emit a warning?
let t2 = Case1 "42" // no error
let xx = x // The value or constructor 'x' is not defined.
In line 3 of the above example, a DU deconstruction was intended, but the compiler silently interprets the line as a function definition. You need to put the left-hand side pattern into parentheses to avoid this. Since the new function shadows the DU constructor, there can be weird follow-up problems that can make the situation difficult to understand.
The mistake is easily made, as patterns usually don't need to be enclosed in parentheses. And the mistake is not that easily found, as illustrated above.
There is a theoretical possibilty that somebody intentionally wants to shadow a DU constructor by a function. I cannot imagine a good use case for it. But even if somebody wants to do it, a warning does not hurt, and it can be suppressed for the file or the compilation.
Additional context
According to both the the language guide (here and here) and the outdated FSharpSpec-4.1 (page 303), let Case1(x) = t
is both a valid function binding and a valid value binding (i.e. in this case DU deconstruction). It seems the compiler silently gives precedence to the function binding.
Fun fact
The example code in this comment in the compiler code base confirms the typical confusion by assuming a union case deconstruction without the parentheses.
Related
EDIT March 2024:
Just in case somebody is looking into this again:
The F# spec actually defines the behavior for this ambiguity in §14.6.1.
And in hindsight, I should have created an analyzer instead of a warning that nobody will ever see.
Metadata
Metadata
Assignees
Type
Projects
Status