17

Does anyone know why this fails to compile?

type MyInterface<'input, 'output> = 
    abstract member MyFun: 'input -> 'output

type MyClass() = 
    interface MyInterface<string, unit> with
        member this.MyFun(input: string) = ()
    //fails with error FS0017: The member 'MyFun : string -> unit' does not have the correct type to override the corresponding abstract method.
type MyUnit = MyUnit
type MyClass2() = 
    //success
    interface MyInterface<string, MyUnit> with
        member this.MyFun(input: string) = MyUnit
Guy Coder
  • 24,501
  • 8
  • 71
  • 136
Stefan Savev
  • 1,319
  • 12
  • 12

1 Answers1

17

This looks like a nasty corner-case in the F# language, but I'm not sure if it qualifies as a by-design limitation or a bug in the compiler. If it is by design limitation, then the error message should say that (because currently, it doesn't make much sense).

Anyway, the problem is that the F# compiler doesn't generate code that actually contains the unit type in the IL. It replaces it with void (when used as a return type) or with empty argument list (when used as a method or function argument).

This means that in the MyClass type, the compiler decides to compile the MyFun member as a method that takes string and returns void (but you cannot use void as a generic type argument, so this just doesn't work). In principle, the compiler could use the actual unit type in this case (because that's the only way to get it working), but that would probably create other inconsistencies elsewhere.

Your trick with creating MyUnit is, I think, a perfectly fine way to solve the problem. Even the core F# library uses something like MyUnit in some places of the implementation (in asynchronous workflows) to deal with some limitations of unit (and the way it is compiled).

Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553
  • Thanks Tomas. I haven't seen this issue elsewhere (e.g. in normal functions with let;) – Stefan Savev Dec 19 '10 at 23:43
  • @Stefan: If you use the `unit` type as argument (to a function or type) then it is generally fine. This bug/limitation probably appears only when implementing abstract members (which is a bit tricky area for the F# compiler, because inheritance is surprisingly complex in .NET) – Tomas Petricek Dec 20 '10 at 00:08
  • 2
    Interestingly, it will work in C# and I can consume the function in F#. Probably should be reported as a bug. – Stefan Savev Jan 12 '11 at 05:55