Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use static extension methods with statically resolved type parameters?

I'd like to use statically resolved type parameters with some extension methods I added to built-in types, like float32 and int32, so I tried the following:

module Foo =
    type System.Single with
        static member Bar x = x + 1.0f

    let inline bar (x : ^a) =
        (^a : (static member Bar : ^a -> ^a) x)

open Foo
[<EntryPoint>]
let main argv =
    System.Console.WriteLine (bar 1.0f) (* Compilation fails here *)
    0

The compiler complains that The type 'float32' doesn't support the operator 'Bar'. What am I doing wrong?

like image 508
Francesco Bertolaccini Avatar asked Aug 05 '17 20:08

Francesco Bertolaccini


1 Answers

Statically resolved type parameters will not resolve against extension methods so this particular approach isn't possible.

I would advise thinking carefully about whether this is something you really need to do or whether you can express the problem you're trying to solve in a different way.

If you are sure that this is what you want and you're willing to brave the dragons that follow, there is a workaround which involves creating a helper type with some static methods:

type Ext = Ext
    with
        static member Bar (ext : Ext, flt : float) = 1.0 + flt
        static member Bar (ext : Ext, flt : float32) = 1.0f + flt

You can then define a new function using statically resolved type parameters like this:

let inline bar (x : ^a) =
    ((^b or ^a) : (static member Bar : ^b * ^a -> ^a) (Ext, x))

Then you can write:

bar 7.0f
val it : float32 = 8.0f

bar 5.0
val it : float = 6.0
like image 75
TheInnerLight Avatar answered Nov 19 '22 21:11

TheInnerLight