Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delay the implementation of interface methods?

Tags:

f#

I've been programming in F# for some years and there's an "issue" that's been bothering me for some time and I have not been able to solve. It is not a bug, I think it is a design decision, but anyway, the problem is this: is there a way to delay (maybe that's not the correct word for this) the implementation of interfaces?, that is, not implementing them in the initial definition, but later, maybe in the same file after I have implemented a module for the type. I'll explain with a simplified example: Suppose I have the following data structure:

    type 'T MyCollection =
        (*type definition*)
        interface IEnumerable<'T> with
            member this.GetEnumerator () =
                (* I don't want to implement it here 
                   because I still don't have the module
                   with a toSeq function *)

If I implemented the method right there, I would have to also implement all the functions as methods of the type and then the module would be just a "proxy" for calling the methods. This way I'm creating a OO-first data structure and then creating a module (overloaded with type annotations) to allow for a functional-first usage. I would prefer to write a functional-first data structure (cleaner since the type inference can work better) and then create a OO wrapper to allow a better intellisense support for languages like C#. That approach complies with what the design guidelines for F# tells us, but the interfaces can't be implemented anywhere but in the initial definition of the type. That restriction forces me to write the whole data structure with members. I've been looking for examples and I've found that the list implementation in FSharp.Core list does exactly what I want, but I can't do that, the compiler won't let me. I'm almost sure that this is a design decision, maybe to avoid encouraging bad practices, I don't know, but I don't consider my wish to be a bad practice. Also I'm well aware of the linear nature of the fsharp compiler.

Please if any of you know how to do what I want, I'll be glad if you tell me. Also, if any of you know why I should not follow this approach I'll be glad to know too. There must be a reason why this is not a problem for anyone else.

Thanks in advance.

like image 974
Enrique A. Casanovas Pedre Avatar asked Jul 06 '15 14:07

Enrique A. Casanovas Pedre


1 Answers

I completely agree that this is unfortunate problem. The trick that is used in the source code of 'a list in the F# Core library is to define the implementation of the interface in a type augmentation. The compiler does not complain when you add members to a type in this way, but it says that adding implementation of an interface in this way is deprecated. However, it does not prevent you from doing this. The following compiles fine for me:

open System.Collections
open System.Collections.Generic

type MyCollection<'T> =
  { Data : 'T list }
  interface IEnumerable<'T> 
  interface IEnumerable 

let getEnumerator { Data = d } = 
  (d :> seq<_>).GetEnumerator()

type MyCollection<'T> with 
  interface IEnumerable<'T> with
    member this.GetEnumerator() = getEnumerator this
  interface IEnumerable with
    member this.GetEnumerator() = (getEnumerator this) :> _

The fact that this is deprecated is a bit unfortunate. I quite like this style and I use it when it makes sense. You can start a discussion about this on F# user voice and perhaps it could be turned back into a normal accepted feature :-)

like image 174
Tomas Petricek Avatar answered Oct 22 '22 13:10

Tomas Petricek