Extension methods for specific generic types
Asked Answered
M

4

11

I'm attempting to create various extension method for a generic type bound to specific generic type parameters in F#, but the language does not seem to be allowing me:

What I want to do is something like the following:

type IEnumerable<int> with
    member this.foo =
        this.ToString()

Yet it gives me the compiler error (underlining the int keyword):

Unexpected identifier in type name. Expected infix operator, quote symbol or other token.

The following does work, though it does not specifically bind the generic type parameter to int, as I want:

type IEnumerable<'a> with
    member this.foo =
        this.ToString()

Is there any way to accomplish this aim in F# - am I perhaps just using the wrong syntax? If not, I would appreciate if someone could suggest a workaround, perhaps using type constraints somewhere.

Milan answered 7/10, 2009 at 13:15 Comment(0)
A
9

This isn't possible in the current version of F#, unfortunately. See related question here.

Aerometry answered 7/10, 2009 at 13:51 Comment(1)
This feature is tracked by a suggestion in the internal F# bug database "4548: Support extension methods for specific type instantiations" but it is unlikely to be make the cut for the VS2010 release.Pianette
S
10

Generic extension methods are now available in F# 3.1:

open System.Runtime.CompilerServices
open System.Collections.Generic

[<Extension>]
type Utils () =
    [<Extension>]
    static member inline Abc(obj: IEnumerable<int>) = obj.ToString()

printfn "%A" ([1..10].Abc())
Stroke answered 22/4, 2014 at 0:54 Comment(0)
A
9

This isn't possible in the current version of F#, unfortunately. See related question here.

Aerometry answered 7/10, 2009 at 13:51 Comment(1)
This feature is tracked by a suggestion in the internal F# bug database "4548: Support extension methods for specific type instantiations" but it is unlikely to be make the cut for the VS2010 release.Pianette
S
1

Well, you can use constraints - but not with sealed types like int.

type IEnumerable<'a when 'a :> InheritableType> =
member this.Blah =
    this.ToString()

Hmm...

Spinnaker answered 7/10, 2009 at 13:31 Comment(2)
Thanks for the suggestion, but indeed, I'm working with a sealed type here, so it doesn't quite work.Milan
This probably doesn't do quite what you think... You're actually defining a new IEnumerable type - try calling the extension on an existing IEnumerable<InheritableType>.Aerometry
S
0

In order to help others looking for similar solutions, here is an example showing how to use generic extension methods with type constraints. In the example below, there is a type constraint requiring that the type argument passed exposes a default constructor. This is done using the [<CLIMutable>] attribute applied to the Order record. Also, I'm constraing the result of the method to the type passed.

In order to use the extension method you have to specify the type you want to use. Note that I'm also extending a generic dictionary interface.

[<Extension>]
type ExtensionMethds () = 

    [<Extension>]
    static member inline toObject<'T when 'T: (new: unit -> 'T)> (dic: IDictionary<string,obj>): 'T =
        let instance = new 'T()
        // todo: set properties via reflection using the dictionary passed in
        instance


[<CLIMutable>]
type Order = {id: int}

let usage = 
    let dictionaryWithDataFromDb = dict ["id","1" :> obj] 
    let theOrder = dictionaryWithDataFromDb.toObject<Order>()
    theOrder
Shauna answered 17/7, 2016 at 1:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.