-
Notifications
You must be signed in to change notification settings - Fork 842
Description
[originally from Connect]
This kind of F# code doesn't work when passing unit as a type argument. If this is an intentional design restriction, the error message should reflect this.
type EDF<'S> =
abstract member Apply : int -> 'S
type SomeEDF1 () =
interface EDF<int> with
member this.Apply d = // OK
123
type SomeEDF2 () =
interface EDF<unit> with
member this.Apply d =
// [ERROR] The member 'Apply : int -> unit' does not have the correct type to override the corresponding abstract method.
()comments
dsyme wrote May 29, 2014 at 6:58 AM [x]
Yes, for F# 3.x this is an intentional design restriction, see http://stackoverflow.com/questions/4485445/f-interface-inheritance-failure-due-to-unit/4485677#4485677 for a longer analysis.You might like to add an issue to http://fslang.uservoice.com to track this, as the F# language spec and implementation could in theory be adjusted to do the appropriate insertion of a "unit" value in the implementation of the override.
I agree that the error message should be improved here.
dsyme wrote May 29, 2014 at 7:17 AM [x]
To summarize - in F#, an abstract slot with declared return type of "unit" gets compiled in .NET IL as a return type of "void". In contrast, an abstract slot with declared return type of "T" gets compiled in .NET IL as a generic return type of "T", which when T is instantiated by "unit" becomes "unit". This means these two slots have logically different characteristics. This difference is one of the few places where the unit<->void translation performed by F# is visible and yes, it affects the overriding rules of the F# language.@antofik asked about the compiler implementation here, specifically IsExactMatch and the check "returnTypesAEquiv" (here in the GitHub code: https://github.com/fsharp/fsharp/blob/6ac6318858da25fe4f1d4728901c5824e9f3bf3a/src/fsharp/tastops.fs#L874 - when will codeplex support links to individual lines :) ).
This operation compares optional TType values representing the return type of the member. None indicates that the return type is logically "void" from the perspective of F# overriding rules, Some(unit-type) or Some (T) indicates the return type is logically "unit" or "T" from the perspective of F# overriding rules.
In terms on nomenclature in the compiler:
- "CompiledForm" of a method signature means that return types are TType options,
"None = type void", and "Some(T) = type T", and "Some(T) under substitution T-->unit = type unit".- "FSharpForm" of a method signature means that return types are TType, and where "void" doesn't occur at all
Note that in the debugger, "None" shows as "null".
dsyme wrote May 29, 2014 at 7:21 AM [x]
To add a better error message, the logical place to put it would be here: https://github.com/fsharp/fsharp/blob/6ac6318858da25fe4f1d4728901c5824e9f3bf3a/src/fsharp/typrelns.fs#L1191"IsExactMatch" would need to be duplicated and adjusted to a "IsExactMatchUpToInstantiatedUnitReturnType". If an override exists satisfying that predicate, then a better error message can then be given, much as for code already present to give a better error message when there is an override satisfying IsPartialMatch or IsNameMatch.
Cheers!
donlatkin wrote Jun 20, 2014 at 6:24 AM [x]
Updating the title to capture specific goal for short term. fslang uservoice can be used to track this as a potential change to the language itself.