tags:

views:

218

answers:

3

The inline keyword in F# seems to me to have a somewhat different purpose than what I'm used to in e.g. C. For example, it seems to affect a function's type (what are "statically resolved type parameters"? Aren't all F# types resolved statically?)

When should I be using inline functions?

+13  A: 

The inline keyword indicates that a function definition should be inserted inline into any code which uses it. Most of the time, this will not have any effect on the type of the function. However, in rare cases, it can lead to a function which has a more general type, since there are constraints which cannot be expressed in the compiled form of the code in .NET, but which can be enforced when the function is being inlined.

The primary case where this applies is the use of operators.

let add a b = a + b

will have a monomorphic inferred type (probably int -> int -> int, but it could be something like float -> float -> float if you have code which uses this function at that type instead). However, by marking this function inline, the F# compiler will infer a polymorphic type:

let inline add a b = a + b
// add has type ^a ->  ^b ->  ^c when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)

There is no way to encode this type constraint in a first class way in compiled code on .NET. However, the F# compiler can enforce this constraint at the site where it inlines the function, so that all operator uses are resolved at compile time.

The type parameters ^a, ^b, and ^c are "statically resolved type parameters", which means that the types of the arguments must be statically known at the site where those parameters are being used. This is in contrast to normal type parameters (e.g. 'a, 'b, etc.), where the parameters mean something like "some type which will be supplied later, but which can be anything".

kvb
+5  A: 

The F# component design guidelines only mention a little about this. My recommendation (that aligns well with what's said there) is:

  • Don't use inline
    • Exception: you might consider using inline when writing mathematical libraries to be consumed by other F# code and you want to write functions that are generic over different numeric data types.

There are lots of other "interesting" uses of inline and static member constraints for "duck-typing" kinds of scenarios that work a bit like C++ templates. My advice is to avoid all of that like the plague.

@kvb's answer goes into more depth about what 'static type constraints' are.

Brian
The `inline` keyword is also extremely useful beyond mathematical libraries. For example, in the context of data structures where it can be used to compose concrete data structures from abstract ones without incurring any run-time performance penalty.
Jon Harrop
+3  A: 

When should I be using inline functions?

The most valuable application of the inline keyword in practice is inlining higher-order functions to the call site where their function arguments are also inlined in order to produce a singly fully-optimized piece of code.

For example, the inline in the following fold function makes it 5× faster:

  let inline fold f a (xs: _ []) =
     let mutable a = a
     for i=0 to xs.Length-1 do
        a <- f a xs.[i]
     a

Note that this bears little resemblance to what inline does in most other languages. You can achieve a similar effect using template metaprogramming in C++ but F# can also inline between compiled assemblies because inline is conveyed via .NET metadata.

Jon Harrop
Is the standard-library fold inlined?
J Cooper
@J Cooper: No but it does convert its function argument to an optimized closure which helps for certain types. The `fold` I gave is ~3× faster than the built-in `Array.fold` when applied to complex numbers, for example.
Jon Harrop
Interesting. Would there be a downside to the built-in using `inline`?
J Cooper
@J Cooper: Don was worried about bloat due to excessive inlining so he keeps things well factored. However, I think this would be ok because C# programmers would write out the explicit loop by hand each time.
Jon Harrop
Man, 3-5x faster... that's a lot! Do you ever resort to using this inline fold over the standard-library folds when developing performance critical libraries?
Stephen Swensen
@Stephen: Yes, all the time. We use `inline` a lot and (counterintuitively) not because of the inlining it performs!
Jon Harrop