7 people like it.

Implement interface by expression

What feature would I like to see in F#? One thing is the ability to implement an interface in a class by delegating the implementation to an expression. This snippet demonstrates the idea using a simple example of vectors.

Background

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
open System

// Let's say we have an interface representing vectors
// (in reality this would have quite a few members)
type IVector =
  abstract Data : seq<float>
  abstract GetValue : int -> float

// Now, we have a concrete vector implementation using an array
type ArrayVector(data:float[]) = 
  interface IVector with
    member x.Data = data |> Seq.ofArray
    member x.GetValue(i) = data.[i]

Currently

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
// And we want to create a "lazy" vector that loads the data
// from database. It has range of values and other operations
// can check for 'DatabaseVector' and instead of actually working
// with in-memory data, they can just adjust min/max date...
//
// When we actually access the data of the vector, this needs
// to load the data from the database and redirect all operations
// to an actual in-memory vector
type DatabaseVector(min:DateTime, max:DateTime) = 
  let vector = Lazy.Create(fun () ->
    let count = int (max - min).TotalDays 
    let data = [| for i in 0 .. count - 1 -> 3.0 |]
    ArrayVector(data) :> IVector)

  // Now we have to implement the interface by writing
  // all the members and just making calls to 'vector' :-((
  interface IVector with
    member x.Data = vector.Value.Data
    member x.GetValue(i) = vector.Value.GetValue(i)

Suggestion

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
type DatabaseVector(min:DateTime, max:DateTime) = 
  let vector = Lazy.Create(fun () ->
    let count = int (max - min).TotalDays 
    let data = [| for i in 0 .. count - 1 -> 3.0 |]
    ArrayVector(data) :> IVector)

  // I would like to be able to say "implement this interface"
  // by delegating all the operations to the object returned by 
  // an expression <expr>. In this example, the expression is just
  // 'vector.Value' (but you can imagine other functions to implement
  // common interfaces like IDisposable, etc...)
  interface IVector = vector.Value
namespace System
namespace Microsoft.FSharp.Data
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
module Seq

from Microsoft.FSharp.Collections
val ofArray : source:'T [] -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.ofArray
val min : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.min
val max : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.max
Multiple items
active recognizer Lazy: Lazy<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.( |Lazy| )

--------------------
type Lazy<'T> = System.Lazy<'T>

Full name: Microsoft.FSharp.Control.Lazy<_>
static member System.Lazy.Create : creator:(unit -> 'T) -> System.Lazy<'T>
Raw view Test code New version

More information

Link:http://fssnip.net/jP
Posted:10 years ago
Author:Tomas Petricek
Tags: interface