The following C# function:
T ResultOfFunc<T>(Func<T> f)
{
return f();
}
compiles unsurprisingly to this:
IL_0000: ldarg.1
IL_0001: callvirt 05 00 00 0A
IL_0006: ret
But the equivalent F# function:
let resultOfFunc func = func()
compiles to this:
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldnull
IL_0003: tail.
IL_0005: callvirt 04 00 00 0A
IL_000A: ret
(Both are in release mode). There's an extra nop at the beginning which I'm not too curious about, but the interesting thing is the extra ldnull
and tail.
instructions.
My guess (probably wrong) is that ldnull
is necessary in case the function is void
so it still returns something (unit
), but that doesn't explain what is the purpose of the tail.
instruction. And what happens if the function does push something on the stack, isn't it stuck with an extra null that doesn't get popped?