3

I am trying to create a type augmentation method for an F# tuple. This code compiles just fine:

type System.Tuple<'a, 'b> with
    member this.ToParameter name =
        match this with
        | this -> sprintf "%s=%O,%O" name (this.Item1, this.Item2)

However, when I try to invoke this method:

printfn "%s" (("cat", 2).ToParameter("test"))

I get an error saying "This field, constructor or member 'ToParameter' is not defined." In the interpreter, the following expressions report their type as being some form of System.Tuple'2:

typedefof<'a * 'b>.FullName
(1, 2).GetType().FullName

In the Visual Studio, if I hover over the expression:

let a = 1, 2

It reports a type of int * int. When I try to augment this type, or it's generic equivalent, 'a * 'b, I get an error.

Is it possible to create a generic augmentation for the F# tuple?

John Atwood
  • 1,505
  • 10
  • 19
  • 1
    Any particular reason for making this an extension method (as opposed to a function)? – pblasucci Feb 24 '13 at 11:55
  • I'd like to be able to call ToParameter on may types. I have the augmentation working for IEnumerable<'a>, string, and others. To create a single function that would handle all of these types, I would have to resort to boxing, and reflection. I could create a different method for each type, but this makes the API less readable. – John Atwood Feb 24 '13 at 19:04
  • 1
    Why not just create a type with overloaded methods - then you would just have `utils.ToParameter(t)` instead of `t.ToParameter()` which would seem ok – John Palmer Feb 24 '13 at 21:04

2 Answers2

4

The answer to your question will be pretty much the same as the answer I gave to a similar question here. That is, the reason why your type extension does not work is because "System.Tuple<_,...,_> is only the encoded form of tuples, and not the static representation used by the compiler. See 6.3.2 Tuple Expressions in the specification."

To use your type extension, you'll have to first box and then cast your tuple value:

let tuple = box ("cat", 2) :?> System.Tuple<string,int>
printfn "%s" (tuple.ToParameter("test"))

Aside: also note that you had a slight syntax error in your type extension, it should be:

type System.Tuple<'a, 'b> with
    member this.ToParameter name =
        match this with
        | this -> sprintf "%s=%O,%O" name this.Item1 this.Item2 //removed parens around Item1 and Item2
Community
  • 1
  • 1
Stephen Swensen
  • 22,107
  • 9
  • 81
  • 136
0

You can use C# style extension methods, but notice you have an error in your definition of ToParameter, arguments should be curried:

open System.Runtime.CompilerServices

[<Extension>]
type TupleExtensions () = 
    [<Extension>] static member ToParameter((a, b), name) = sprintf "%s=%O,%O" name a b

printfn "%s" (("cat", 2).ToParameter("test"))

The reason why using System.Tuple doesn't work it's because at compile-time .NET tuples and F# syntactic tuples they are treated as different types. This might change in future versions of the compiler.

Gus
  • 25,839
  • 2
  • 51
  • 76