Question

I usually try to make my questions more generic, but this time I think the example case makes the issue much clearer. I am also new to F#, so trying to generalize too much might be a mistake at this stage :)

What I want to achieve is to create a function that returns the appropriate BitConverter.ToXXX function for a given type argument. Here is what I tried:

let FromBytes<'a> : (byte[] * int -> 'a) = 
  match typeof<'a> with
  | x when x = typeof<Int16> -> BitConverter.ToInt16
  | x when x = typeof<UInt16> -> BitConverter.ToUInt16
  | _ -> failwith "Unknown type"

However, this fails because the compiler doesn't understand that the types are guaranteed to match up.

I'm sure I can find a workaround, but is there a way to make this work without changing the function signature?

Was it helpful?

Solution

You need to cast the final value:

let FromBytes<'a> : (byte[] * int -> 'a) = 
  match typeof<'a> with
  | x when x = typeof<Int16>  -> downcast (BitConverter.ToInt16  |> box)
  | x when x = typeof<UInt16> -> downcast (BitConverter.ToUInt16 |> box)
  | _ -> failwith "Unknown type"

This will check the type at run-time and select the proper case, there is also a trick to do it at compile time using static constraints, but if you are learning it might be really confusing:

open System
type T = T with
    static member ($) (T, _: int16) = fun v s -> BitConverter.ToInt16 (v,s)
    static member ($) (T, _:uint16) = fun v s -> BitConverter.ToUInt16(v,s)
    static member ($) (T, _: int  ) = fun v s -> BitConverter.ToInt32 (v,s)
    static member ($) (T, _:uint32) = fun v s -> BitConverter.ToUInt32(v,s)

let inline fromBytes (value:byte[], startIndex:int) = 
    (T $ Unchecked.defaultof< ^R>) value startIndex : ^R

// usage
let (x:int   ) = fromBytes([|255uy;0uy;0uy;255uy|], 0)
let (y:uint16) = fromBytes([|255uy;0uy;0uy;255uy|], 0)

The F# compiler inlines the required function at the call site, you can't call the generic function from C#.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top