The inline
keyword allows function bodies to be directly inserted in place of calls to them. This can be a powerful optimization tool but should be used judiciously as not all functions are good candidates for inline behavior. The following example demonstrates the basic usage:
class Main { static inline function mid(s1:Int, s2:Int) { return (s1 + s2) / 2; } static public function main() { var a = 1; var b = 2; var c = mid(a, b); } }
The generated JavaScript output reveals the effect of inline:
(function () { "use strict"; var Main = function() { } Main.main = function() { var a = 1; var b = 2; var c = (a + b) / 2; } Main.main(); })();
As evident, the function body (s1 + s2) / 2
of field mid
was generated in place of the call to mid(a, b)
, with s1
being replaced by a
and s2
being replaced by b
. This avoids a function call which, depending on the target and frequency of occurrences, may yield noticeable performance improvements.
It is not always easy to judge if a function qualifies for being inline. Short functions that have no writing expressions (such as a =
assignment) are usually a good choice, but even more complex functions can be candidates. However, in some cases, inlining can actually be detrimental to performance, e.g. because the compiler has to create temporary variables for complex expressions.
Inline is not guaranteed to be done. The compiler might cancel inlining for various reasons or a user could supply the --no-inline
command line argument to disable inlining. The only exception is if the class is extern or if the class field has the extern
access modifier, in which case inline is forced. If it cannot be done, the compiler emits an error.
It is important to remember this when relying on inline:
class Main { public static function main() {} static function test() { if (Math.random() > 0.5) { return "ok"; } else { error("random failed"); } } @:extern static inline function error(s:String) { throw s; } }
If the call to error
is inlined the program compiles correctly because the control flow checker is satisfied due to the inlined throw expression. If inline is not done, the compiler only sees a function call to error
and emits the error A return is missing here
.
Since Haxe 4 it is also possible to inline specific calls to a function or constructor, see inline
expression.
The inline
keyword can also be applied to variables, but only when used together with static
. An inline variable must be initialized to a constant, otherwise the compiler emits an error. The value of the variable is used everywhere in place of the variable itself.
The following code demonstrates the usage of an inline variable:
class Main { static inline final language = "Haxe"; static public function main() { trace(language); } }
The generated JavaScript shows that the language
variable is not present anymore:
(function ($global) { "use strict"; var Main = function() { }; Main.main = function() { console.log("root/program/Main.hx:5:","Haxe"); }; Main.main(); })({});
Note that even though we call such kind of fields "variables", inline variables can never be reassigned as the value must be known at compile-time to be inlined at the place of usage. This makes inline variables a subset of final
fields, hence the usage of the final
keyword in the code example above.
Trivia:
inline var
Prior to Haxe 4, there was no
final
keyword. The inline variables feature however was present for a long time, using thevar
keyword instead offinal
. Usinginline var
still works in Haxe 4 but might be deprecated in the future, becausefinal
is more appropriate.