Question

This came up while I looked at the following question: F# Unit of Measure, Casting without losing the measure type Please note that I am not trying to use this unbox code, I just discovered some weird behavior while answering the question.

Why does the following code work

let intToFloat (x:int<'u>) : float<'u> = unbox float x
intToFloat 1<second>

while this yields a System.InvalidCastException: Unable to cast object of type 'float32ToFloat@86-6' to type 'Microsoft.FSharp.Core.FSharpFunc`2[System.Single,System.Double]'.?

let float32ToFloat (x:float32<'u>) : float<'u> = unbox float x
float32ToFloat 1.0f<second>

If I put parantheses around the (float x) the code works as expected, so I assume it must be some expression evaluation/type inference rule. What exactly is going on here and why are the parantheses needed in the second case?

Was it helpful?

Solution

The subtle thing in your code snippets is unbox float x - the compiler treats this as (unbox float) x. As a result the two functions are actually treated like this:

let intToFloat (x:int<'u>) : float<'u> = 
  let f = unbox float in f x

let float32ToFloat (x:float32<'u>) : float<'u> = 
  let f = unbox float in f x

So, you are taking the float function, casting it (unsafely) to a function of another type and then calling it. The type is int<'u> -> float<'u> in the first case and float32<'u> -> float<'u> in the second case.

I think the first one works because when the compiler sees the float function (without any type annotations), it defaults to int -> float and, since units of measure are erased at runtime, this can be converted to int<'u> -> float<'u> (but not to the second type - because you are performing unsafe cast).

So, the main problem is wrong parentheses in your implementation (which leads to a really subtle issue). I think you probably wanted something like this:

let intToFloat (x:int<'u>) : float<'u> = unbox (float x)
let float32ToFloat (x:float32<'u>) : float<'u> = unbox (float32 x)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top