inline - How does nesting f# functions differ from not nesting them when nesting is optional? -
i understand benefit of nesting functions when want return closure. when function never used outside of function defined in, there cost keeping nested?
consider:
let private validate number = number > 100 let validateandprint (i : int) = printfn "%i greater 100: %s" ((validate i).tostring())
versus:
let validateandprint (i : int) = let validate number = number > 100 printfn "%i greater 100: %s" ((validate i).tostring())
the concern here when have few of these inner functions , need call 1 of them based on execution path (it's not prohibitive keep these functions private or nested , test permutations).
validateandprint
rewritten more tdd-friendly take in validate function:
let validateandprint validate = ...
..but if validation
's signature contains internal or private type there consideration of making public , parameter list blowing up.
any crucial differences?
in release
mode, il identical , both versions of validate
inlined in particular example.
you cannot rely on inlining always, e.g. if function "big" compiler choose not inline (this true methods, not 100% sure true f# nested functions. not possible mark them inline
, force inlining, - need consult f# specs if such functions behave methods or inlined in release). in nested case in debug mode, there additional fsharpfunc allocation , callvirt
. without nesting static call without allocations, cheapest of possible implementations.
so in general, if nesting optional safer avoid it, because if function not inlined called static method. however, matters when call code several millions times per second.
not nested, static call on il_0019:
.method public static void validateandprint ( int32 ) cil managed { // method begins @ rva 0x2104 // code size 51 (0x33) .maxstack 5 .locals init ( [0] class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, [1] bool ) il_0000: ldstr "%i greater 100: %s" il_0005: newobj instance void class [fsharp.core]microsoft.fsharp.core.printfformat`5<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit, class [mscorlib]system.tuple`2<int32, string>>::.ctor(string) il_000a: call !!0 [fsharp.core]microsoft.fsharp.core.extratopleveloperators::printformatline<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>>(class [fsharp.core]microsoft.fsharp.core.printfformat`4<!!0, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit>) il_000f: stloc.0 il_0010: nop il_0011: ldloc.0 il_0012: newobj instance void fsso.test/validateandprint@8::.ctor(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>) il_0017: ldarg.0 il_0018: ldarg.0 il_0019: call bool fsso.test::validate(int32) il_001e: stloc.1 il_001f: ldloca.s 1 il_0021: constrained. [mscorlib]system.boolean il_0027: callvirt instance string [mscorlib]system.object::tostring() il_002c: call !!0 class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, string>::invokefast<class [fsharp.core]microsoft.fsharp.core.unit>(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!0, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!1, !!0>>, !0, !1) il_0031: pop il_0032: ret } // end of method test::validateandprint
nested, allocation on il_0018 , callvirt on il_0020:
.method public static void validateandprint ( int32 ) cil managed { // method begins @ rva 0x2050 // code size 58 (0x3a) .maxstack 6 .locals init ( [0] class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, bool> validate, [1] class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, [2] bool ) il_0000: newobj instance void fsso.test2/validate@13::.ctor() il_0005: stloc.0 il_0006: ldstr "%i greater 100: %s" il_000b: newobj instance void class [fsharp.core]microsoft.fsharp.core.printfformat`5<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit, class [mscorlib]system.tuple`2<int32, string>>::.ctor(string) il_0010: call !!0 [fsharp.core]microsoft.fsharp.core.extratopleveloperators::printformatline<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>>(class [fsharp.core]microsoft.fsharp.core.printfformat`4<!!0, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit>) il_0015: stloc.1 il_0016: nop il_0017: ldloc.1 il_0018: newobj instance void fsso.test2/'validateandprint@14-2'::.ctor(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>) il_001d: ldarg.0 il_001e: ldloc.0 il_001f: ldarg.0 il_0020: callvirt instance !1 class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, bool>::invoke(!0) il_0025: stloc.2 il_0026: ldloca.s 2 il_0028: constrained. [mscorlib]system.boolean il_002e: callvirt instance string [mscorlib]system.object::tostring() il_0033: call !!0 class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, string>::invokefast<class [fsharp.core]microsoft.fsharp.core.unit>(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!0, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!1, !!0>>, !0, !1) il_0038: pop il_0039: ret } // end of method test2::validateandprint
release mode, inlined comparison on il_0020:
.method public static void validateandprint ( int32 ) cil managed { // method begins @ rva 0x2050 // code size 57 (0x39) .maxstack 6 .locals init ( [0] class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, [1] class [fsharp.core]microsoft.fsharp.core.printfformat`4<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit>, [2] bool ) il_0000: ldstr "%i greater 100: %s" il_0005: newobj instance void class [fsharp.core]microsoft.fsharp.core.printfformat`5<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit, class [mscorlib]system.tuple`2<int32, string>>::.ctor(string) il_000a: stloc.1 il_000b: call class [mscorlib]system.io.textwriter [mscorlib]system.console::get_out() il_0010: ldloc.1 il_0011: call !!0 [fsharp.core]microsoft.fsharp.core.printfmodule::printformatlinetotextwriter<class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>>(class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.printfformat`4<!!0, class [mscorlib]system.io.textwriter, class [fsharp.core]microsoft.fsharp.core.unit, class [fsharp.core]microsoft.fsharp.core.unit>) il_0016: stloc.0 il_0017: nop il_0018: ldloc.0 il_0019: newobj instance void fsso.test2/'validateandprint@14-2'::.ctor(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<string, class [fsharp.core]microsoft.fsharp.core.unit>>) il_001e: ldarg.0 il_001f: ldarg.0 il_0020: ldc.i4.s 100 il_0022: cgt il_0024: stloc.2 il_0025: ldloca.s 2 il_0027: constrained. [mscorlib]system.boolean il_002d: callvirt instance string [mscorlib]system.object::tostring() il_0032: call !!0 class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<int32, string>::invokefast<class [fsharp.core]microsoft.fsharp.core.unit>(class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!0, class [fsharp.core]microsoft.fsharp.core.fsharpfunc`2<!1, !!0>>, !0, !1) il_0037: pop il_0038: ret } // end of method test2::validateandprint
Comments
Post a Comment