unit
elimination logic can lead to unutterable & unimplementable signatures
#17611
Labels
Area-Compiler-Checking
Type checking, attributes and all aspects of logic checking
Impact-Low
(Internal MS Team use only) Describes an issue with limited impact on existing code.
Milestone
(This is not new, is low-impact, is likely a known thing, and likely cannot be fixed, but I'm recording it anyway.)
The way
unit
elimination works in the compiler means that(())
is sometimes equivalent to()
and sometimes not (see, e.g., #16254).Sometimes, both
(())
and()
may compile tovoid
or the absence of a parameter; other times, both may compile toMicrosoft.FSharp.Core.Unit
; other times still,(())
may compile toMicrosoft.FSharp.Core.Unit
and()
to the absence of a parameter.An interesting corollary to this is that it is possible to define an overloaded method each of whose overloads compiles differently while having an identical F# type signature:
It is thus impossible to specify a signature for this type and its method overloads that will compile — both overloads have the same F# signature:
That means that it is also impossible to declare such overloads on an interface or abstract class in F#. This is another way of saying that it's impossible to write an F# signature describing the C# signature
void M(Unit _arg1)
.None of these compile:
It is possible to define such an interface in C#, however:
Such a C# interface can then be implemented from F# like:
On the other hand, it's also possible to define an interface in C# like the following:
This interface is impossible to implement in F#:
What does this all amount to? Not much, since changing the
unit
elimination logic or using parentheses for differentiation (member M : unit -> unit
=void M()
,member M : (unit) -> unit
=void M(Unit _arg1)
) as is done for tuples would be backwards-incompatible.Too bad .NET didn't just use
unit
instead ofvoid
from day 1 🙂The text was updated successfully, but these errors were encountered: