F# Type Casts

Typecast matters are complicated in F#. Unlike many other languages, F# does not perform implicit upcasts by default. E.g. if class Derived derives from Base, and we have

let func( b : Base ) = ...
let d : Derived  = ...

then func(d) will not work. The compiler will complain that type Derived is not compatible with Base. This comes as a shock to an object-oriented developer. We must explicitly “upcast” derived class to base class like this: func (upcast d) or func (d :> Base). In the former case, F# automatically figures out the destination type, in the latter case we explicitly say what it is.

Alternatively, we can explicitly declare f as accepting a polymorphic argument:

let func( b : #Base ) = ...

I believe that internally this it implemented via generics. with actual argument type becoming a template parameter.

Overall, F# introduces five typecast operators:

Operation F# C# Explanation
upcast upcast x x Automatically deduce destination type T from context and cast x to T. Static type of x must be a subtype of T, or the code will not compile.
:> x :> T (T)x Cast x to T. Static type of x must be a subtype of T, or the code will not compile.
downcast downcast x no equivalent Automatically deduce destination type T from context and cast x to T. Static type of x must be a base class of T, or the code will not compile.
:?> x :?> T x as T If dynamic type of x is T or is derived from T, returns (T)x. Otherwise returns null, even if T is not a class type. Static type of x must be a base class of T, otherwise compilation error occurs.
:?  if x ?: T then if (x is T) Returns true if dynamic type of x is T or is derived from T, otherwise returns false. Static type of x must be a base class of T, or the code will not compile.

In addition to the typecast operators, F# uses pattern matching operator ?: [as variable], e.g.

let func (x:Base) =
 match x with
  | :? TwiceDerived as td -> td_func td
  | :? Derived -> 10
  | _ -> 0

Some notes:
* There are too many cast operators, and their spelling are quite confusing. I am afraid not many people can intuitively tell what a :?> might mean.
* Polymorphism is applied inconsistently. E.g. it does not work in function calls by default, but it does work in the :? operator. In the above example, if actual type of x is DerivedFromDerived, :? Derived will still work

Posted in

2 Comments


  1. All of your blog posts about F# contain really serious errors. In this case, your first line of code is wrong (it should be “b : #Base”) and everything that follows is wrong as a consequence.

    Reply

  2. b: Base is not an error. This line of code works exactly as I describe.
    If I declare f(b : #base), the call will indeed become polymorphic, but this is not how it works in other languages.
    In other languages you can use derived wherever you use base (Liskov substitution principle).
    But it is worth noting that you can have explicit polymorphism via #.
    I will edit the post accordingly.
    Thanks

    Reply

Leave a Reply to Jon Harrop Cancel reply

Your email address will not be published. Required fields are marked *