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?
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 followingfold
function makes it 5× faster: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 becauseinline
is conveyed via .NET metadata.You should use inline when you need to define a function that must have its type (re)evaluated at the site of each usage, as opposed to a normal function, which will have its type evaluated (inferred) only at the site of first usage, and then be regarded as being statically typed with that first inferred type signature everywhere else thereafter.
In the inline case, the function definition is effectively generic/ polymorphic, whereas in the normal (none-inline) case, the function is statically (and often implicitly) typed.
So, if you use inline, the following code:
will build, and compile to produce the following output:
In other words, the same add function definition has been used to produce both a function that adds to integers, and a function that concatenates two strings (in fact the underlying operator overloading on + is also achieved under the hood using inline).
Whereas this code, identical except that the add function is no longer declared inline:
will not compile, failing with this complaint:
A good example of where using inline is appropriate, is when you want to define a generic function to reverse the order of the application of arguments of a function with 2 arguments, e.g.
as is done in the answer from @pad to this question Different argument order for getting N-th element of Array, List or Seq.
The F# component design guidelines only mention a little about this. My recommendation (that aligns well with what's said there) is:
inline
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.
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.
will have a monomorphic inferred type (probably
int -> int -> int
, but it could be something likefloat -> 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: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".