What is the difference between the following F# casting operators? I can't seem to understand why and how they are all different.
(type) X
X :> type
X :?> type
The first isn't a cast in F#, though if you're used to C# it might appear that it works like one. But this is actually invoking a type conversion function (like int
), and the parentheses aren't actually required (and are just likely to make everything more confusing).
(int) "4" // the number 4 - this is a conversion, not a cast
int "4" // same thing, but idiomatic
int "NaN" // compiles but throws an exception at runtime
(int) (box 4) // doesn't compile because int doesn't do downcasts, just known conversions
Note that this works for primitive types, because there are predefined conversion functions, but it won't work for arbitrary types:
(bigint) 1 // no such conversion function, so this is a compile-time error
The difference between the other two is that :>
performs upcasts (from a type to a supertype, which is always safe) and :?>
performs downcasts (from a type to a subtype, which might fail, thus the '?'
in the middle).
There are also named upcast
and downcast
operators which can be used in a similar way:
5 :> obj // upcast int to obj
(upcast 5 : obj) // same
(box 5) :?> int // downcast an obj to int (successfully)
(downcast (box 5) : int) // same
(box "5") :?> int // downcast an obj to int (unsuccessfully)
In some contexts the target type of the upcast or downcast may be successfully inferred, in which case you don't need the type annotations when using the upcast
or downcast
operators, while you always need to provide a type argument to the :>
or :?>
operators (though you can supply _
if you expect it to be inferred):
List.map (fun x -> x + 1) (downcast (box [1]))
List.map (fun x -> x + 1) (box [1] :?> _)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With