Reputation: 7757
I'm trying to create a function in F# that will convert certain types to a string, but not others. The objective is so that a primitive can be passed but a complex object cannot be passed by accident. Here's what I have so far:
type Conversions =
static member Convert (value:int) =
value.ToString()
static member Convert (value:bool) =
value.ToString()
let inline convHelper< ^t, ^v when ^t : (static member Convert : ^v -> string) > (value:^v) =
( ^t : (static member Convert : ^v -> string) (value))
let inline conv (value:^v) = convHelper<Conversions, ^v>(value)
Unfortunately, my conv
function gets the following compile-time error:
A unique overload for method 'Convert' could not be determined based on type information
prior to this program point. A type annotation may be needed. Candidates:
static member Conversions.Convert : value:bool -> string,
static member Conversions.Convert : value:int -> string
What am I doing wrong?
Upvotes: 3
Views: 196
Reputation: 11362
For some reason it seems using (^t or ^v)
in the constraint instead of just ^v
makes it work.
type Conversions =
static member Convert (value:int) =
value.ToString()
static member Convert (value:bool) =
value.ToString()
let inline convHelper< ^t, ^v when (^t or ^v) : (static member Convert : ^v -> string)> value =
( (^t or ^v) : (static member Convert : ^v -> string) (value))
let inline conv value = convHelper<Conversions, _>(value)
Of course it means the function will also compile if the argument's type has a static method Convert
from itself to string, but it's highly unlikely to ever bite you.
Upvotes: 4
Reputation: 7757
Well, Daniel's answer worked. Here's what I wanted in the end:
type Conversions = Conversions with
static member ($) (c:Conversions, value:#IConvertible) =
value.ToString()
static member ($) (c:Conversions, value:#IConvertible option) =
match value with
| Some x -> x.ToString()
| None -> ""
let inline conv value = Conversions $ value
The IConvertible
interface type is just a convenient way for me to capture all primitives.
This results in the following behavior (FSI):
conv 1 // Produces "1"
conv (Some 1) // Produces "1"
conv None // Produces ""
conv obj() // Compiler error
Upvotes: 2
Reputation: 47904
This seems to work:
type Conversions = Conversions with
static member ($) (Conversions, value: int) = value.ToString()
static member ($) (Conversions, value: bool) = value.ToString()
let inline conv value = Conversions $ value
conv 1 |> ignore
conv true |> ignore
conv "foo" |> ignore //won't compile
Upvotes: 6