// thinkbeforecoding

C# Static interfaces - Take 3

2013-04-03T22:09:52 / jeremie chassaing

You may believe it or not, but the post that drains most of the traffic of this blog, is the one about C# static interfaces !

 

In october 2009, I simply tried to imagine where the idea of C# static interfaces could lead us, and, since then, I have more viewed pages (> 15%) on this post than on my home page !

 

And since then, nothing moved in this area in the C# langage, and I don’t expect it to happen soon.

 

But some other thing happened…

 

F#

 

Yes F# is out and running on almost all platforms, and it can do what I described in the previous post.

 

The thing is called Statically Resolved Type Parameters and is closer to C++ templates than from C# generics.

 

The trick is that you can define an inline function with statically resolved types, denoted by a ^ prefix. The usage of defined methods on the type is not given here by an interface, but by a constraint on the resolved type :

let inline count (counter: ^T=
    let value = (^T: (member Count : intcounter) 
    value

here , the count function takes a counter of type ^T (statically resolved).

The second line express that ^T actually should have a member Count of type int, and that it will call it on counter to get the result value !

 

Magic !

 

Now, we can call count on various types that have a Count member property like :

type FakeCounter() =
    member this.Count = 42;

or

type ImmutableCounter(count: int=
    member this.Count = count;
    member this.Next() = ImmutableCounter(count + 1)

or

type MutableCounter(count: int=
    let mutable count = 0
    member this.Count = count;
    member this.Next() = count <- count + 1

without needing an interface !

For instance :

let c = count (new FakeCounter())

True, this is compile time duck typing !

 

And it works with methods :

let inline quack (duck: ^T=
    let value = (^T: (member Quack : int -> string) (duck3))  
    value

This will call a Quack method that takes int and returns string with the value 3 on any object passed to it that has a method corresponding to the constraint.

And magically enough, you can do it with static methods :

let inline nextThenstaticCount (counter: ^T=
    (^T: (member Next : unit -> unitcounter)
    let value = (^T: (static member Count : int) ()) 
    value

this function calls an instance method called Next, then gets the value of a static property called Count and returns the value !

It also works with operators :

let inline mac acc x y = acc + x * y

notice the signature of this function :

acc: ^a -> x: ^c -> y: ^d ->  ^e
    when ( ^a or  ^b: (static member ( + ) :  ^a *  ^b ->  ^eand
         ( ^c or  ^d: (static member ( * ) :  ^c *  ^d ->  ^b)

It accepts any types as long as they provide expected + and * operators.

 

The only thing is that a specific implementation of the function will be compiled for each type on which it’s called. That’s why it called statically resolved.

 

You can use this kind of method from F# code but not from C#.

 

Anyway…

No need for static interfaces in C#, use F# !