Q:

F# Downcasting Slow?

I have a situation where I need to downcast twice in one procedure using :?>. I have a custom EventArgs class (which inherits System.EventArgs), and an instance of an abstract class within that custom EventArgs. Upon receiving the event, I need to downcast twice. Once for the custom EventArgs, and once for the abstract class within that custom EventArgs. I have to do this potentially millions of times a day, so I'm wondering if there's anything inherently slow about downcasting.

A:

For grins, I put together the following little function:
let castToStream (o:Object) = o :?> Stream

and called it with the following code:
[<EntryPoint>]
let main argv = 
    let stm1 = new FileStream("output.tmp", FileMode.Create, FileAccess.ReadWrite, FileShare.Read)
    let obj = stm1 :> Object
    let stm2 = castToStream obj
    0 // return an integer exit code

When it is compiled, castToStream turns into this IL:
.method public static class [mscorlib]System.IO.Stream 
    castToStream(object o) cil managed
{
  // Code size       8 (0x8)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  unbox.any  [mscorlib]System.IO.Stream
  IL_0007:  ret
} // end of method Program::castToStream

which in this case is effectively 1 real instruction, unbox.any. Unbox.any for a reference type is equivalent to a castclass instruction. From the description, you'll take a one-time initial hit to load the type if it's not already loaded, then it's going to be a whatever magic is necessary to determine if the types are equivalent (likely using Type.IsAssignableFrom(), but I don't know for sure). However, unless your class hierarchy is super deep (and it shouldn't be), I would expect this to take microseconds on a typical machine.
For the curious, I initially had the code for castToStream inline, but the f# compiler saw through my shenanigans and removed all the casting entirely.

