A few days ago @jxxcarlson wrote this thread Performance Optimization on small changes in how equality gets written in the source code and how it had a huge impact on performance for a function that was called many many times.
The example given was the following:
Before
ensureNonBreakingSpace : Char -> Char
ensureNonBreakingSpace char =
if char == ' ' then
nonBreakingSpace
else
char
After
ensureNonBreakingSpace : Char -> Char
ensureNonBreakingSpace char =
case char of
' ' ->
nonBreakingSpace
_ ->
char
The explanation was that the comparison done in the first example called _Utils_eqHelp
, which is a very slow function compared to a simple ===
comparison in JavaScript.
I have looked at the compiled output, and I am very confused about the result and explanations, because from what I can see, this only applies when Elm is compiled without --optimize
.
Here are the JS output for both code versions, with and without optimizations enabled.
// Before version, uncompiled
var $author$project$Review$Rule$ensureNonBreakingSpace = function (_char) {
return _Utils_eq(
_char,
_Utils_chr(' ')) ? $author$project$Review$Rule$nonBreakingSpace : _char;
};
// Before version, compiled
var $author$project$Review$Rule$ensureNonBreakingSpace = function (_char) {
return (_char === ' ') ? $author$project$Review$Rule$nonBreakingSpace : _char;
};
// After version, uncompiled
var $author$project$Review$Rule$ensureNonBreakingSpace = function (_char) {
if (' ' === _char.valueOf()) {
return $author$project$Review$Rule$nonBreakingSpace;
} else {
return _char;
}
};
// After version, uncompiled
var $author$project$Review$Rule$ensureNonBreakingSpace = function (_char) {
if (' ' === _char) {
return $author$project$Review$Rule$nonBreakingSpace;
} else {
return _char;
}
};
Without --optimize
, there is a big difference in the output, and I believe there is a huge difference in performance. But with --optimize
, both versions are almost identical and neither uses _Utils_eq
.
I know someone that tried using this type of comparison on a parser and they saw a 16x performance boost. But they were benchmarking without --optimize
. This sparked discussions on how we could make tooling to improve the performance, using code transformation on the Elm code or JS code. But once when running with --optimize
, there was no difference. I am now wondering whether the comments on that thread and the potential related benchmarks were based on the non-optimized output.
I would really like to understand whether writing code like in the “after” example would improve performance on the code I write. As an author of a tool that I’d like to make as fast as possible, this is valuable information. I am guessing that there are some situations where changing how the code is written in Elm makes a difference in the output, but I don’t think this is one of them.
I would love to have misunderstood something, and for there to be easy performance wins, so please let me know if I did.