Assuming we have a list of list of numbers that for a reason unimportant to the presented case we want to represent as arithmetic operations:
var list = [[0, 360/2], [0, 360/3, 360/3*2],... [0,... 180+40+(30*2)]];
On top of that we want to do some more calculations on each of these numbers, lets assume angles and rotate -90 degree, but keep all values positive.
var rotate = (num) => { num < 90 ? num + 270 : num - 90 };
var process = list => list.map(_ => _.map(_ => rotate(_));
Lets also say that we have some code that later on randomly can access any of the values, thus any compiler should:
- retain all values
- possibly calculate them on compile time*
At this point I would expect the resulting code to look something like this:
var a = [[270,90],....[270,...]];
This is not the case with either Google Closure compiler nor Dart2JS compiler.
Interestingly GCC did calculate the initial numbers (before rotation) but only if the result is an integer, if the result was a floating point number it was left as it is (i.e. 360/7 was lest as is). The call to the process method was left intact as well as the logical operand in rotate.
Dart2JS did something similar, but it calculated all initial numbers including the ones resulting in floating point numbers. However calls to both functions was left in the resulting code.
Still I was sure there has to be a way to tell the compilers that those numbers should all be pre-calculated and used directly by the VM instead of running calculations on startup. (Yes, I know how fast JS is with simple arithmetic and that several numbers will not slow down the start of the app, but this is just an experiment).
Next step was to try and take out the logical operator from the rotating function:
var rotate = n => n - 90;
This will allow negative numbers to go inside the list but for our use case it was okay. Mind you, however that this can significantly change the behavior in other cases, so it might not be appropriate to do in your case.
Still the result was not what I expected in both GCC and Dart2JS.
I was determined to force the compiler to inline the results... somehow.
Next step was to wrap each number in a direct call to the original rotate function. Yes, no one would write the code like this, but little regexp and voila:
var list = [[rotate(0), rotate(360/2)], .... [.... rotate(180+40+(30*2))]];
Still, no luck in GCC numbers resulting in integers were calculated, but wrapped in the minified identifier for the rotatte function:
var a = [[a(0), a(180)]...];
Same with Dart2JS as before, all numbers calculated before the rotation including floats.
Finally I tried with the simplified (no logical operators) rotate function and GCC gives us this:
var a = [[-90,90],... [...225]];
Note that we still had to compromise with allowing negative values. Of course still preserving the non-integers as original arithmeric expression. It finally hit me - GCC optimizes for size, not for speed or anything else. 360/7 is much shorter than 51.42857142857143
Dart2JS continues to insist that we call a function to make the calculation with minus 90...
We have come a long way in FE with adding compilers and transpilers of all sorts, however we still cannot expect miracles .. or in this case consise understanding of our intent when it comes to little 3d grade arithmetics.
Next step would be to see how does this compile in Rust to target web assembly!