Lay González
Lay González

Reputation: 2985

How to write an extension method for a generic type, where one type variable has to be string?

In particular, I want to write an extension method for this type:

type Frame<'TRowKey, string when 'TRowKey : equality> with
  member frame.someMethod =
    // code

With that code, I'm getting this error:

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

replacing string with String gives the same result.

The original type is Frame<'TRowKey, 'TColumnKey (requires equality and equality)> from the Deedle library.

Upvotes: 3

Views: 329

Answers (2)

Gus
Gus

Reputation: 26184

I don't have Deedle to test this code but you should use .NET extension methods:

open System

[<Runtime.CompilerServices.Extension>]
module Extensions =
    [<Runtime.CompilerServices.Extension>]
    let someMethod<'TRowKey when 'TRowKey : equality> (frame :Frame<'TRowKey, string>) = // body

This is the same way that scrwtp calls 'the idiomatic way' (I don't like to go into discussions about idomaticity) but at the same time it will work from C# as an extension method.

If you want to use it from F# as well as an extension, it has to be declared as a type:

[<Runtime.CompilerServices.Extension>]
type Extensions =
    [<Runtime.CompilerServices.Extension>]
    static member someMethod<'TRowKey when 'TRowKey : equality> (frame :Frame<'TRowKey, string>) = // body

So now you can type row. and intellisense will only shows the extension if it its second parameter is a string.

Upvotes: 2

scrwtp
scrwtp

Reputation: 13577

@Gustavo gave a thorough answer of how to get it working with extension methods. But If you don't have a particularly strong reason for this being an extension method (like C# interop), you might just go with a simple function:

type Frame<'row, 'col> = { row: 'row; col: 'col }

module Frame = 
    let restricted (frame: Frame<'row, string>) = frame

Frame.restricted { row = 3; col = "test" } // compiles
Frame.restricted { row = 3; col = 5 }      // doesn't

That's what I'd consider a cleaner approach when writing F#-only code - let-bound functions preferable to methods when they don't make sense as an intrinsic part of the type, and less noise from the attributes.

Upvotes: 5

Related Questions