We had a custom parser in our build toolchain in Perl that needed ~40min for a normal build. I rewrote it in F# (similar performance to C#) and got it down to 3min. Because I thought it was fun I ported it to Rust, and it now runs in 15 secs (mostly because of memory safe, zero-copy string handling and generally better control of memory allocation).
Probably in C# it could have been a bit faster than in F# if you use some of the optimization capabilities. But I doubt you could get close to Rust. Even reading one of the files in .NET takes as long as Rust takes for everything.
In C++ it would definitely be possible to reach Rust performance, it's just way harder to keep your memory intact without the borrow-checking compiler.
Now I don't know how Perl and JS compare, but I'd guess they're in a similar ballpark for performance.
I still doubt JS/V8 is faster than one of the VM languages (.NET or JVM), they don't need to be interpreted and have much less dynamic stuff so they can optimize better.
If you rewrote something like Closure Compiler in C, I doubt you could get more than a 2x-4x speedup. The bigger fruit lay in minimizing the amount of work you do each time through the optimization loop.
The problem with most hobby projects that write transpilers is, people take a simple app like TodoMVC and say "look how amazing the edit/refresh is with this transpiler", but design decisions made early can come back to bite you much later when you're trying to handle a codebase with hundreds of thousands of lines.
Transpiled higher level languages tend to encourage people to create many layers of abstraction and re-use a ton of existing libraries, which tends to bloat the inputs to the compiler.
Really good point. Closure Compiler, at least historically, rejected many valid optimizations because they aren't common enough to justify growing the rate of number of passes.
> If you rewrote something like Closure Compiler in C, I doubt you could get more than a 2x-4x speedup.
Closure Compiler is written in Java. I don't know exactly where the state of the art of JIT is right now, but I would bet C wouldn't be that much faster.
More importantly, this is a compiler targeted towards one-time compilations to permanently reduce large JavaScript payloads per millions of downloads, and not a compiler that is required during development. As such, blunting its effect to save a few seconds is pretty meaningless, so I doubt the maintainers ever considered "less optimization".
That said, it does allow for "dangerous" but more aggressive optimizations that require assurances from the JavaScript or you'll break the code. In that way, Closure offers user-specified levels of optimization.
EDIT: A secondary and less-obvious effect is that using a smaller number of total optimizations produces more internally-consistent code, as opposed to producing unusual and internally-unique constructions for rare optimizations. Internal consistency is great for the next step after compilation: run-length compression.
Yes, but still, some projects are orders of magnitude larger than other projects. Also, some users might be willing to wait an hour, others only a minute.
There are, essentially, an infinite number of optimizations you could make to Closure, though probably several thousand are reasonable. Every marginal optimization needs to run though the entire AST and many of them require prior optimizations to be re-run. As 'cromwellian pointed out, the number of passes is the dominating factor in speed. At some point, it's no longer worth it.
For Google production code, we typically let things run long, because if you shave off say, 30k from Gmail * 1 billion active users, you've just saved a lot of bandwidth.
I'd be interested in seeing what a large typescript project would look like run through https://github.com/angular/tsickle.
https://github.com/google/closure-compiler
https://github.com/BuckleScript/bucklescript
https://github.com/fastpack/fastpack
Seems like on the average it does offer a boost in performance.
And there is some aditional work providing javascript parsers for rust (which you could build tools like babel on top of): https://github.com/dherman/esprit
But I believe the topic here was about runtime performance of using a language to compile JS, not about the build speed of working in that language itself. In which case you’ll still get some wins writing a JS toolchain in BuckleScript (compiled to JS), just from the JiT-friendliness of the BuckleScript JS output.
But realistically, you’d be compiling to native OCaml through the same codebase. We did see a 10-25x perf jump from converting a part of a Babel pipeline to native OCaml. I mean, these languages are basically designed over decades with AST manipulation in mind, so that’s not surprising.
I certainly thought about writing this in Rust or C++, and still plan on exploring that. Still, it's nice to stay in the JS world, e.g. easy integration with webpack and all of the other tools.