-
Notifications
You must be signed in to change notification settings - Fork 833
Description
(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 to void or the absence of a parameter; other times, both may compile to Microsoft.FSharp.Core.Unit; other times still, (()) may compile to Microsoft.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:
type T () =
member _.M () = () // public void M() { }
member _.M (()) = () // public void M(Unit _arg1) { }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:
member T.M : unit -> unitThat 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:
type U =
abstract M : unit -> unit
abstract M : unit -> unittype U =
abstract M : unit -> unit
abstract M : (unit) -> unittype U =
abstract M : unit -> unit
abstract M : _arg1:unit -> unitIt is possible to define such an interface in C#, however:
public interface U
{
void M();
void M(Microsoft.FSharp.Core.Unit _arg1);
}Such a C# interface can then be implemented from F# like:
type T () =
interface U with
member _.M () = ()
member _.M (()) = ()On the other hand, it's also possible to define an interface in C# like the following:
public interface U
{
void M(Microsoft.FSharp.Core.Unit _arg1);
Microsoft.FSharp.Core.Unit M();
}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 of void from day 1 🙂
Metadata
Metadata
Assignees
Labels
Type
Projects
Status
