> So, your article is FUD in it's purest undistilled form.
The article is just reiterating an argument that Mozilla and Facebook made. If you’re saying Mozilla and Facebook are spreading Fear Uncertainty and Doubt with their proposal for a binary JS AST, then you may do so, but please realize that they probably had good reasons to start such a project.
EDIT: Even though I disagree with the parent, it is making some good points (specifically, that WebASM is going to add a GC), so flagging it to death doesn’t seem to be the right thing to do.
Yes, dmitriid, I believe it's clear by now that you don't like this project.
As I mentioned in another conversation, if you feel you can contribute to Wasm and make it solve the problems we are solving here, this is great, by all means, please do so.
In the meantime, we are going to continue trying to solve some of the performance problems of the web using the techniques discussed in the blog entry because we are convinced that they are going to work better.
This is some amazing progress, but reading this and hearing how difficult JavaScript is as a language to design around makes me wonder how many hours have we spent optimizing a language designed in 2 weeks and living with those consequences. I wish we could version our JavaScript within a tag somehow so we could slowly deprecate code. I guess that would mean though browsers would have to support two languages that would suck..... this really is unfortunately the path of least resistance.
(I understand I could use elm, cjs, emscriptem or any other transpirer but I was thinking of ours spent around improving the js vm.
3. Deployed Scripting Media Types and Compatibility
Various unregistered media types have been used in an ad-hoc fashion
to label and exchange programs written in ECMAScript and JavaScript.
These include:
+-----------------------------------------------------+
| text/javascript | text/ecmascript |
| text/javascript1.0 | text/javascript1.1 |
| text/javascript1.2 | text/javascript1.3 |
| text/javascript1.4 | text/javascript1.5 |
| text/jscript | text/livescript |
| text/x-javascript | text/x-ecmascript |
| application/x-javascript | application/x-ecmascript |
| application/javascript | application/ecmascript |
+-----------------------------------------------------+
And along these lines: javascript modules automatically turn strict mode on, so most people will just be on the "new" (strict) version of javascript once modules are popular.
Brendan Eich was on a podcast in 2016 talking about the origins and evolution of JS. At one point he and the ECMA team wanted to make == strict equality, but then that would have required specifying the JS version, and Microsoft didn't like that, so they decided to go with === and leave == non-strict.
It's one of several cases where backward compatibility on the web trumped cleaning up the language.
So, compiled Javascript then? "We meet again, at last. The circle is now complete."
The more I see interpreted languages being compiled for speed purposes, and compiled languages being interpreted for ease-of-use purposes, desktop applications becoming subscription web applications (remember mainframe programs? ), and then web applications becoming desktop applications (electron) the more I realize that computing is closer to clothing fads than anything else. Can't wait to pickup some bellbottoms at my local target.
You are obviously very passionate and I believe that nothing I can write will convince you, so I will not pursue this conversation with you after this post.
For the same reason, my answers here are for people who have not followed the original HN thread in which we have already had most of this conversation.
I also believe that the best way for you to demonstrate that another approach is better than the JavaScript Binary AST would be for you to work on demonstrating your approach, rather than criticizing this ongoing work.
> - WebAssembly does not support JS hence we need binary AST
> WebAssembly is on track to support dynamic and GC-ed languages
If/when WebAssembly gains the ability to interact with non-trivial JS objects, JS libraries, etc. we will be able to compare the WebAssembly approach with the Binary AST approach. GC support and dynamic dispatch are prerequisites but are not nearly sufficient to allow interaction with non-trivial JS objects and libraries.
So let's meet again and rediscuss this if/when this happens.
> - WebAssembly will be slower than binary AST
> You've provided zero support for this statement. Meanwhile experiments with real apps (like Figma) show significant improvements with WebAssembly
If you recall, we are only talking about loading speed. I believe that there is no disagreement on execution speed: once WebAssembly implementations are sufficiently optimized, it is very likely that well-tuned WebAssembly code will almost always beat well-tuned JS code on execution.
The argument exposed on the blog is that:
- attempting to compile JavaScript to existing WebAssembly is very hard (hard enough that nobody does it to the best of my knowledge);
- the specifications of JavaScript are complex enough that every single object access, every single array access, every single operator, etc. is actually a very complex operation, which often translates to hundreds of low-level opcodes. Consequently, should such a compilation take place, I suspect that this would considerably increase the size of the file and the parsing duration;
- by opposition, we have actual (preliminary) numbers showing that compressing to JavaScript Binary AST improves both file size and parse time.
While I may of course be wrong, the only way to be sure would be to actually develop such a compiler. I have no intention of doing so, as I am already working on what I feel is a more realistic solution, but if you wish to do so, or if you wish to point me to a project already doing so, I would be interested.
You refer to the experiments by Figma. While Figma has very encouraging numbers, I seem to recall that Figma measured the speedup of switching from asm.js to WebAssembly. In other words, they were measuring speedups for starting native code, rather than JS code. Also a valid experiment, but definitely not the same target.
> - No one wants to ship bytecode
> False
Are we talking about the same blog entry?
What I claimed is that if we ended up with one-bytecode-per-browser or worse, one-bytecode-per-browser-version, the web would be much worse than it is. I stand by that claim.
> - it's hard to align browsers on bytecode
> See WebAssembly
I wrote the following things:
- as far as I know, browser vendors are not working together on standardizing a bytecode for the JavaScript language;
- coming up with a bytecode for a language that keeps changing is really hard;
- keeping the language-as-bytecode and the language-as-interpreted in sync is really hard;
- because of the last two points, I do not think that anybody will start working on standardizing a bytecode for the JavaScript language.
In case of ambiguity, let me mention that I am part of these "browser vendors". I can, of course, be wrong, but once again, let's reconvene if/when this happens.
> in which we have already had most of this conversation.
Interestingly enough, nowhere do you even mention these conversations in your attempts to push binary AST as hard as possible.
> Consequently, should such a compilation take place, I suspect that this would considerably increase the size of the file and the parsing duration;
Emphasis above is mine. However, it's presented (or was presented) by you as a fact.
> What I claimed is that if we ended up with one-bytecode-per-browser or worse, one-bytecode-per-browser-version, the web would be much worse than it is. I stand by that claim.
We are ending up with one wasm bytecode for every browser, aren't we?
> as far as I know, browser vendors are not working together on standardizing a bytecode for the JavaScript language;
Because they are working together on standardizing bytecode for the web in general, aren't they?
> coming up with a bytecode for a language that keeps changing is really hard
So you're trying to come up with a binary AST for a language that keeps changing :-\
> keeping the language-as-bytecode and the language-as-interpreted in sync is really hard
What's the point of WebAssembly then?
> I do not think that anybody will start working on standardizing a bytecode for the JavaScript language.
Because that's not really required, is it? This is a non-goal, and never was the goal. The goal is to create an interoperable standardized bytecode (akin to JVM's bytecode or .Net's MSIL), not a "standardized bytecode for Javascript". For some reason you don't even want to mention this.
> I claimed that no browser vendor seriously contemplates exposing their internal bytecode format
They don't need to.
> Additionally, the JavaScript Binary AST is designed in such a manner that evolutions of the JavaScript language should not break existing parsers.
I shudder to think how rapidly changing languages like Scala, ClojureScript etc. can ever survive on the JVM. The horror!
> If/when that day arrives, I'll compare both approaches.
Basically you will end up with two representations of JS: a binary AST and a version that compiles to WASM. Oh joy. Wasn't this something you wanted to avoid?
Regardless of all your points, the fact is that WASM isn't ready for this now, and doesn't appear that it will be for some time.
Combined with the fact, as mentioned above, that DOM access is significantly slower means that WASM isn't a suitable candidate. This is something you forgot to mention or take into account in your comment, for some reason.
Yes this does seem to overlap a bit with wasm as you have noted, but saying "well we could get this optimization but we need to wait several years until this highy complex other spec is completely finished" doesn't seem as good.
Why not do this, and use wasm when it's available? Why can't you have both?
> Regardless of all your points, the fact is that WASM isn't ready for this now
As opposed to Binary AST which as available now? :)
> Combined with the fact, as mentioned above, that DOM access is significantly slower
Given that DOM access for WASM currently happens via weird interop through JavaScript (if I'm not mistaken) how is this a fact?
> "well we could get this optimization but we need to wait several years until this highy complex other spec is completely finished" doesn't seem as good.
No. My point is: "Let's for once make a thing that is properly implemented, and not do a right here right now short-sighted short-range solution"
That's basically how TC39 committee operates these days: if something is too difficult to spec/design properly, all work is stopped and half-baked solutions are thrown in "because we need something right now".
> Why not do this, and use wasm when it's available? Why can't you have both?
Because this means:
- spreading the resources too thin. There is a limited amount of people who can do this work
- doing much of the work twice
- JS VM implementors will have to support text-based parsing (for older browsers), new binary AST and WASM
... because DOM access is significantly (10x) slower? That alone rules out your approach right now, regardless of the other points raised.
> Because this means: ...
When you understand how weak these arguments are you will understand the negative reaction to your comments on this issue.
You're clearly very passionate about this issue but you don't seem to be assessing the trade offs. Having something right now and iterating on it is better than waiting an indeterminate amount of time for a possible future solution involving an overlapping but otherwise unrelated specification that has not been fully implemented by anyone to a satisfactory point, and one with very complex technical issues blocking its suitability.
Sure, it would be nice to use WASM for this, but it is in no way needed at all. Given the status of WASM and the technical issues present with using it in this way it is odd to champion it to such a degree.
It seems your entire arguments boil down to "WASM may be OK to use at some point in the future, stop working on this and wait!". I, and I'm assuming others, don't see this as a very convincing point.
If I may, I'd offer some advice: stop taking this issue to heart. Time will tell if you're right, and making borderline insulting comments to the technical lead of the project in an attempt to push your position doesn't help anyone.
The world is heating up and species are dying, there are much better causes to take to heart.
I may be mistaken, but I believe Adobe had to ship an Actionscript 2 runtime forever because they completely replaced it when they introduced AS3. They needed to keep the flash player backwards compatible, so the player had to have both runtimes. While it worked, it was a kludge.
Webassembly is pretty much a greenfield approach: you need to learn C, redo your whole codebase and still write JS code to load your wasm, interact with DOM and browser APIs, and leverage existing good enough JS libraries. This is the state of things as of 2017. It took 4 years to reach that point. If you want to bet everything on the state of wasm in 2-3 years from now, please be my guest. Meanwhile, I have a business to run.
The binary AST is a quick win for brownfield technology, with already a working version in an experimental Firefox build. It can be rolled quite fast. It improves right now the experience of many users on existing codebase the same way minification did. And improve the experience of current web assembly, as it is still largely dependent on the speed of JS. I'll take this feature any day.
How can you say it's "compressed" over "compiled" when you are actually parsing it into an AST and then (iiuc) converting that to binary? That's exactly what compilers do. You are in fact going to a new source format (whatever syntax/semantics your binary AST is encoded with) so you really are compiling.
To be fair, these two concepts are similar and I may be totally misunderstanding what this project is about. In the spirit of fairness, let me test my understanding. You are saying wasm bytecode is one step too early and a true "machine code" format would be better able to improve performance (especially startup time). I'm not following wasm development, but from comments here I am gathering that wasm is too level and you want something that works on V8. Is that what this project is about?
On a side note, it's truly a testament to human nature that the minute we get close to standardizing on something (wasm), someone's gotta step up with another approach.
> If you prefer, this Binary AST representation is a form of source compression, designed specifically for JavaScript, and optimized to improve parsing speed.
> How can you say it's "compressed" over "compiled" when you are actually parsing it into an AST and then (iiuc) converting that to binary? That's exactly what compilers do. You are in fact going to a new source format (whatever syntax/semantics your binary AST is encoded with) so you really are compiling.
I am not sure but there may be a misunderstanding on the word "binary". While the word "binary" is often used to mean "native", this is not the case here. Here, "binary" simply means "not text", just as for instance images or zipped files are binary.
A compiler typically goes from a high-level language to a lower-level language, losing data. I prefer calling this a compression mechanism, insofar as you can decompress without loss (well, minus layout and possibly comments). Think of it as the PNG of JS: yes, you need to read the source code/image before you can compress it, but the output is still the same source code/image, just in a different format.
> You are saying wasm bytecode is one step too early and a true "machine code" format would be better able to improve performance (especially startup time). I'm not following wasm development, but from comments here I am gathering that wasm is too level and you want something that works on V8. Is that what this project is about?
No native code involved in this proposal. Wasm is about native code. JS BinAST is about compressing your everyday JS code. As someone pointed out in a comment, this could happen transparently, as a module of your HTTP server.
> On a side note, it's truly a testament to human nature that the minute we get close to standardizing on something (wasm), someone's gotta step up with another approach.
Well, we're trying to solve a different problem :)
Posting this in the hope that it might help some people grok what they are actually doing:
When I first discovered what Yoric and syg were doing, the first thing that I thought of was old-school Visual Basic. IIRC when you saved your source code from the VB IDE, the saved file was not text: it was a binary AST.
When you reopened the file in the VB6 IDE, the code was restored to text exactly the way that you had originally written it.
The parent might have been thinking of QuickBasic, which saved programs as byte-code, along with formatting information to turn it back into text: http://www.qb64.net/wiki/index.php/Tokenized_Code
BBC Basic did this too -- keywords were stored as single bytes (using the 128-255 values unused by ASCII). Apart from that the program code wasn't compiled, it just was interpreted directly. Very smart design when everything had to fit in 32KB of RAM.
> Here, "binary" simply means "not text", just as for instance images or zipped files are binary.
If it's not text, then what is it? I'm not sure "not text" is a good definition of the word "binary".
> A compiler typically goes from a high-level language to a lower-level language, losing data.
I don't agree, I don't think there is any loss in data, the compiled-to representation should cover everything you wanted to do (I suppose not counting tree-shaking or comment removal).
> I prefer calling this a compression mechanism, insofar as you can decompress without loss (well, minus layout and possibly comments).
Ahh, so you mean without losing the original textual representation of the source file.
> Wasm is about native code
Here you are making claims about their project that are just not the whole picture. Here's the one-line vision from their homepage[1]:
> WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.
With that description in mind, how do you see BinAST as different?
> Well, we're trying to solve a different problem :)
I think you might be misunderstanding what wasm is intended for. Here's a blurb from the wasm docs that is pertinent:
> A JavaScript API is provided which allows JavaScript to compile WebAssembly modules, perform limited reflection on compiled modules, store and retrieve compiled modules from offline storage, instantiate compiled modules with JavaScript imports, call the exported functions of instantiated modules, alias the exported memory of instantiated modules, etc.
The main difference I can gather is that you are intending BinAST to allow better reflection on compiled modules than wasm intends to support.
Here's another excerpt from their docs (and others have mentioned this elsewhere):
> Once GC is supported, WebAssembly code would be able to reference and access JavaScript, DOM, and general WebIDL-defined objects.
Text means a sequence of characters conforming to some character encoding. Yoric's binary AST is not a sequence of characters conforming to a character encoding.
Compilation maps a program in a higher level language to a program in a lower level language. The map is not required to be one-to-one: the colloquial term for this is "lossy."
Parsing is unavoidable, regardless if the code is interpreted or compiled.
This proposal seems to further compress the AST somehow.
Basically the idea is to already preprocess the text source, so that the client can skip two steps on execution: lexical analysis and the parsing of the text source resulting in the AST. The post explains why the authors believe that this is a good idea.
You seem to assume that there is One True Way of doing things and we're just circling round trying to find it. In fact, as you point out, there are benefits and tradeoffs to every approach. People compile interpreted languages to make them run faster, but are using them in the first place because they're easier to use. People who have come to compiled languages for speed are now naturally looking to make them easier to develop with as well.
Compiled C is not going to go away any sooner than interpreted Javascript - but a widening of the options available is great as it allows us to focus on developing things quickly and correctly, rather than making decisions based on which particular annoyance you're happy to put up with.
People try to move CS both towards and away from engineering: We want the dependability engineering seems to provide in, say, Civil Engineering, but we don't want to acknowledge that engineering is about trade-offs, which are compromises, and that the nature of those trade-offs changes as the world surrounding a specific tool or program changes.
Maybe they think there is a One True Way. Maybe they think every building needs to be reinforced concrete and structural steel, now and forever, in every possible context.
That is what on my ideal world ChromeOS should have been, but with Dart instead, unfortunately the ChromeOS team had other plans in mind and made it into a Chrome juggler OS.
I was using Smalltalk on some university projects, before Sun decided to rename Oak and announce Java to the world.
The development experience was quite good.
Similarly with Native Oberon, which captured many of the Mesa/Cedar workflows.
> That is what on my ideal world ChromeOS should have been, but with Dart instead,
That would have been very interesting. I liked Dart from the brief time I looked at it. The web still feels like a somewhat crippled platform to develop for.
I think everything will eventually settle in the middle where Java and C# currently live.
They have an "intermediate code" that they somewhat compile down to. But this is really a more compact version of the source than a binary though. You can see this easily by running a decompiler. Often times the decompiled IL is almost identical to the source. And before the JIT kicks in the IL is typically interpreted.
You get the best of both worlds. Easy to compile, easy to decompile, platform agnostic, compact code, and fast if it needs to be
It's not optimal for things like embedded, device drivers, high performance computing, etc. So I doubt everything will settle there. There will always be situations where C/Rust/Fortran are better choices.
The Design of Everyday Things is instructive here. You don't design for the middle or the average. You design for the extreme edges. If you have a programming language that can be used both by absolute beginners who just want to learn enough programming to script their excel spreadsheet AND HFT traders who need to ring out every cycle of performance they can on every core they have at their disposal, then the middle will take care of itself.
Software development is fad driven, I think a lot or most people would agree with this. I myself find this to be lamentable. But over the years I've asked myself, why is this the case? I mean it has been faddish for years, this isn't new in the current era.
I think there are two main drivers for fad-ism in software. One is we as developers, are required to chase the popular languages and frameworks to stay current, marketable, and employable. So there is always a sense of "what do I have to learn next, so I can switch jobs succesfully when I need to". Another driver is, developers seek to gain experience by re-doing things from the past. Example, creating new languages, or compiler for an existing language, provides inexperience developers with fantastic new experiences and knowledge. This is desirable.
So yeah, we got fads, and us old timers, or not so old timers with a historical perspective, watch our lawns, but everyone has to learn somehow. Ideally a lot of this would come from an apprenticeship/journeyman system, or a University degree of some sort. But for now it's all we have.
To me, software development seems as tribal as politics. People tend to like and agree with those in their own tribe, and tend to see criticism of their tribe's preferred ideology as an attack on their identity.
There's a lot of pressure to be part of a popular tribe, and so you see situations where even a mild criticism of, for example, the a piece of the JavaScript tribe's technology (like, say, npm or Webpack) tends to elicit vitriolic responses and counter arguments.
You can sometimes get away with this kind of criticism if you choose your words carefully and make it very clear (or at least pretend to) that you're actually a member of the tribe you're criticizing, and that your criticism is meant to be constructive. So you say something like 'I use npm, and I like it, but here's where I struggle with it and here's how I'd improve it'. But if you just write about why you dislike it, you're likely to be flamed and criticized, even if everything you wrote verifiably correct.
So I find that watching programmers argue in blogs and on HN and Reddit feels a lot like reading political arguments on Reddit, or Facebook. And maybe that's why programming tends to be faddish. Each tribe is mostly only aware of its own history; there's no real shared sense of culture, or much awareness of the rich shared history that got us to where we are today. And so you see lots of wheel reinvention, as people poorly re-solve problems that were already solved long ago by other programming tribes.
These are just my personal observations, though. I could very well be completely wrong. :)
Part of this is fad driven, but part of this is also driven by other human concerns. For example, had the early web been binary (like we're pushing for now) instead of plain text it would have died in its crib. Executing binary code sent blindly from a remote server without a sandbox is a security nightmare. Now that we have robust sandboxes, remote binary execution becomes a viable option again. But, it took a decade's worth of JVM R&D to get to this point.
There is a serious problem when every new generations of a technology fixates on some problem of its choice and ignores all the others. The issue of binary blobs didn't go away. What changed is that a lot of developers today don't care about the open nature of the web and are perfectly fine with sacrificing it for faster load times of their JS-saturated websites.
I think a much better approach to this pronblem would be a compression format that's designed specifically for JavaScript. It could still be negotiable, like GZIP, so anyone wanting to see the source would be able to see it. It could also be designed in a way that allows direct parsing without (full?) decompression.
> What changed is that a lot of developers today don't care about the open nature of the web and are perfectly fine with sacrificing it for faster load times of their JS-saturated websites.
I'm one of those developers who couldn't care less about the 'open nature of the web'. I understood the necessity of it to the early, emerging internet, but times have changed. Now that we have secure sandboxes and the web is choking on its own bloat, it's time to shift back to binary blobs.
How does adding more code to the browser stack prevent the web from "choking on its own bloat"? You need to take things away to reduce bloat, not add them.
And they all had crippling security problems[1]. I only mentioned the JVM, but you're right, all of those technologies contributed to the work of secure sandboxes.
[1]: Except maybe Silverlight. From what I remember, it didn't see enough success to be a tempting target for hackers.
This isn't driven by a "fad", rather by the simple fact that any trace of JS engine performance will show a sizable chunk at the beginning dedicated to just parsing scripts. Heck, we even have "lazy parsing", where we put off doing as much parsing work as possible until a piece of code is needed. Replacing that with a quick binary deserialization pass is a straightforward win.
I wouldn't call this "compiled JavaScript". In broad strokes what's happening is you take the result of parsing JavaScript source to an AST and serialize that; then next time you deserialize the AST and can skip the parsing stage.
(Source: I spent a summer working on JS engine and JIT performance at Mozilla.)
I don't think the point was that this project is a fad.
Instead, I think the point was that Javascript is a fad (we'll see whether this is true by watching how popular compile-to-WASM languages become compared to JS, once WASM becomes widespread and stable).
Alternatively, we might say that JS was created (in 10 days, yadda yadda) at a time when the fads were dynamic typing over static typing; interpreters over compilers; GC over manual or static memory management; OOP over, say, module systems; imperative over logic/relational/rewriting/etc.; and so on. JS's role as the Web language has tied developers' hands w.r.t. these tradeoffs for 20 years; long enough that a significant chunk of the developer population hasn't experienced anything else, and may not really be aware of some of these tradeoffs; some devs may have more varied experience, but have developed Stockholm Syndrome to combat their nostalgia ;)
As an example, one of the benefits of an interpreter is that it can run human-readable code; this is a sensible choice for JS since it fits nicely with the "View Source" nature of the Web, but it comes at a cost of code size and startup latency. The invention of JS obfuscation and minifiers shows us that many devs would prefer to pick a different balance between readability and code size than Eich made in the 90s. This project brings the same option w.r.t. startup latency. WASM opens up a whole lot more of these tradeoffs to developers.
Actually I think it was created at a time where it was used very sparingly and had very limited scope. The joke used to be that the average javascript program is one line. I don't know if that was ever exactly true but a lot of early javascript was on inline event attributes (think "onclick" and the like).
For that use a forgiving scripting language is a good fit. What changed is what javascript, and the web, is used for. Embedded Java and Flash showed that there was an appetite for the web to do more and the security problems involved with those technologies showed they weren't a good fit.
Javascript was adapted to fill that void by default as it was the only language that every browser could agree on using.
Haha, I did enjoy this comment. It's kinda fair, but also kinda not.
At each step developers are trying to create the best thing they can with the tools at their disposal. There will always be a tradeoff between flexibility and ease of use. There's a reason Electron exists — the browser has limitations that are easier to work around in Electron. There's a reason we moved to putting stuff online, we could write it once and distribute it everywhere.
> At each step developers are trying to create the best thing they can with the tools at their disposal.
Well, yeah. The point is that we don't have a consistent definition of "best" that's constant over time. Only by changing your direction all the time can you end up walking in circles.
You're not the only one to observe that computing tends to be fad-driven. I enjoy Alan Kay's take on it:
In the last 25 years or so, we actually got something like a pop culture, similar to what happened when television came on the scene and some of its inventors thought it would be a way of getting Shakespeare to the masses. But they forgot that you have to be more sophisticated and have more perspective to understand Shakespeare. What television was able to do was to capture people as they were.
So I think the lack of a real computer science today, and the lack of real software engineering today, is partly due to this pop culture.
...
I don’t spend time complaining about this stuff, because what happened in the last 20 years is quite normal, even though it was unfortunate. Once you have something that grows faster than education grows, you’re always going to get a pop culture.
...
But pop culture holds a disdain for history. Pop culture is all about identity and feeling like you're participating. It has nothing to do with cooperation, the past or the future — it's living in the present. I think the same is true of most people who write code for money. They have no idea where [their culture came from] — and the Internet was done so well that most people think of it as a natural resource like the Pacific Ocean, rather than something that was man-made. When was the last time a technology with a scale like that was so error-free? The Web, in comparison, is a joke. The Web was done by amateurs.
I wish I've heard/seen some of the Alan Kay talks/articles earlier in my career. The more I work in IT, the more I see the wisdom in how he sees the industry. (And I don't just mean these pop culture comments.)
I feel fortunate to have seen his talks and interviews early in my career.
The downside is that exposure to both of those led me to write some software in both Smalltalk and Common Lisp...which is a downside because having worked with those makes some currently popular tools seem like dirty hacks.
Although I use things and enjoy things like React, and Webpack, and npm and I'm very happy with the things I'm able to create with them, when I stop and think about it, the tooling and building/debugging workflow feels pretty disjointed to what was available in Smalltalk and CL environments 30 years ago.
I understand why those tools didn't win over the hearts and minds of developers at the time. They were expensive and not that easily accessible to the average developer. I just wish that as an industry, we'd at least have taken the time to understand what they did well and incorporate more of those lessons into our modern tools.
Fads, or steadfast pursuit of balancing tradeoffs and finding clever ways to improve tools?
Compilation and interpretation both have distinct advantages. It's hard to do both (read: it took a while) and each has tradeoffs.
I'm impressed and grateful that I can get compile time errors for interpreted languages, and I'd feel the same about being able to use a compiled lang in a repl.
Regarding the actual topic at hand, this isn't compiled JavaScript, just parsed JavaScript. They're shipping an AST, not bytecode/machine code.
Indeed. That's not one of the main goals of the project, but I hope that standardizing the AST will help a lot with JS tooling, including code visualisation.
I want to see a code editor that represent common programming language concepts such as classes, functions (OO) in a graphical way and displays the rest in text.
This is a really interesting project from a browser technology point of view. It makes me wonder how much code you'd need to be deploying to for this to be useful in a production environment. Admittedly I don't make particularly big applications but I've yet to see parsing the JS code as a problem, even when there's 20MB of libraries included.
The specifications are not nearly stable enough to be publicized yet. In particular, there are several possibilities for file layout, compression, etc. and we have barely started toying with some of them, so any kind of spec we publish at this stage would be deprecated within a few weeks.
If you wish to follow the development of the reference implementation, you can find it here: https://github.com/Yoric/binjs-ref/ . It's very early and the format will change often as we
Here's some perspective for where this project is coming from:
> So, a joint team from Mozilla and Facebook decided to get started working on a novel mechanism that we believe can dramatically improve the speed at which an application can start executing its JavaScript: the Binary AST.
I really like the organization of the present article, the author really answered all the questions I had, in an orderly manner. I'll use this format as a template for my own writing. Thanks!
Personally, I don't see the appeal for such a thing, and seems unlikely all browsers would implement it. It will be interesting to see how it works out.
Oh, I think I misunderstood you. You mean the AST is going to go the way of Native Client because Mozilla doesn't have the muscle it used to? Or do you think Google's going to sandbag it as revenge for Native Client? :)
> Personally, I don't see the appeal for such a thing, and seems unlikely all browsers would implement it.
Facebook can just run a feature detection JS snippet to see if your browser supports the Binary AST, and select the URLs of the other JS assets accordingly. If Binary AST is a thing, I can easily see web frameworks implementing such a format selection transparently.
And hey, if it contributes to people perceiving Firefox as faster than Chrome, I'm all for it. :)
It's going through TC39 (the committee that decides how the JavaScript language should evolve) and recently reached stage 1 (proposals advance from stage 0 to stage 4). I believe that if it reaches stage 4, then that means that all browser vendors have agreed to implement it, so it certainly seems to be their goal.
From an alternate "not the web" viewpoint, I am interested in this because we have a desktop application that bootstraps a lot of JS for each view inside the application. There is a non-insignificant chunk of this time spent in parsing and the existing methods that engines expose (V8 in this case) for snapshotting / caching are not ideal. Given the initial reported gains, this could significantly ratchet down the parsing portion of perceived load time and provide a nice boost for such desktop apps. When presented at TC39, many wanted to see a bit more robust / scientific benchmarks to show that the gains were really there.
Yoric is working on a "proper" implementation and I'll be assisting in the design work, and if needs be some implementation. I think the next milestone here is a working demo in Firefox with Facebook page load.
At a personal level, I feel pretty confident that BinaryJS will help your case. The theory behind the gains was pretty solid before we designed the prototype. The prototype, for me, basically proved the theory.
My personal hope is that by the time we're done squeezing all we can out of this - which includes zero-costing lazy function parsing, and on-line bytecode generation, we can cut the "prepare for execution" time by 80%.
Do you have any details on what could be improved wrt V8's snapshotting? We have recently extended the feature set a lot in order to be able to snapshot full Blink contexts, and there are some efforts on-going to implement that in Node.js as well. Soon crutches like electron-link won't be necessary anymore.
To clarify how this is not related to WebAssembly, this is for code written in JavaScript, while WASM is for code written in other languages.
It's a fairly simple optimization - it's still JavaScript, just compressed and somewhat pre-parsed.
WASM doesn't currently have built-in garbage collection, so to use it to compress/speed up/whatever JavaScript, you would have to compile an entire JavaScript Virtual Machine into WASM, which is almost certainly going to be slower than just running regular JavaScript in the browser's built-in JS engine.
(This is true for the time being, anyway. WASM should eventually support GC at which point it might make sense to compile JS to WASM in some cases.)
This is important, as there seems to be a lot of misunderstanding in this thread.
What's proposed is structural compression of JS with JS-specific bits to speed things up even more. What's proposed is not compiled JS, in that the original JS is not meaningfully transformed at all. There is a very explicit design goal to retain the original syntactic structure.
OTOH WebAssembly is like a new low-level ISA accessible from web browsers. To use wasm, one does have to compile to it. As the parent here says, compiling JS -> wasm currently requires at least a GC but also much more. To engineer a performant VM and runtime for a dynamic programming language like JS is a time-consuming thing. It is curious to see so many folks think that JS can straightforwardly be compiled to wasm. Currently wasm and JS serve very different needs; and I also don't think JS will be going anywhere for many, many years.
This is a very good point. I would also add that there are a lot of languages compiling to JavaScript that would similarly not benefit from wasm. Right now, pretty much all GC-ed languages compiling to JS (such as ClosureScript, Elm, Scala.js, BuckleScript, PureScript, etc.) are in that category. Even if/when wasm supports GC in the future, I expect that dynamically typed languages compiling to JS will still be a long way from benefiting from wasm.
However, all these languages can benefit from the Binary AST right away. Just like any codebase directly written in JavaScript. If the Binary AST has some decent story about position mapping (see [1] which I just filed), they might even get somewhat better tooling/debugging support going through the Binary AST than going through .js source files, out of the box.
For context: position mapping is somewhere on our radar, but we haven't reached a stage at which it would make sense to start working on it yet.
If you have ideas and/or spare cycles, of course, they are welcome :)
As a side-note: I believe that we could build upon the (very early) proposed mechanism for comments to also store positions. Size-optimized BinAST files would drop both comments and positions, while debugging-optimized BinAST files would keep both at the end of the file so as to not slow down parsing until they are needed.
That seems awesome. I'm glad that it's on your radar.
If you can point me to the best place to suggest ideas or spend my spare cycles, I would gladly do so. At the very least, I can comment on how we serialize positions in the (tree-based) Scala.js IR, which is size-optimized.
Off-topic: I'm sorry to go a little squishy, but I thought I should say that I appreciate the work both of you do very much... though sjrd's work is a little bit more "direct-impact-for-me" at the moment, I must admit. :p
Of course, as you just both said, your work is kind of complementary... which is always nice. :)
Anyway, thanks for the long-term thinking to the both of you.
A lot of the languages you mentioned have different enough memory allocation characteristics than JavaScript due to immutability and functional style that they would probably benefit from having a garbage collector tuned to their purposes in webassembly. There's a reason we don't have one common garbage collector for all the managed languages.
I do recognize that this is a side point, but I think it's worth mentioning.
A lot of the mentioned languages also allow deep interoperability between their heap and the JavaScript heap, e.g., circular references between objects of the "two heaps", and free access to fields and methods of objects of the other language.
That's very hard (if not impossible) to achieve without leak and performance degradation if the two languages have their own GC, with their own heaps.
Compiling a language to JS is not about making it work. That's easy (it becomes hard to cite a language that does not do it). It's about designing the language to interoperate with JS, and making that work. That is the real challenge.
> Compiling a language to JS is not about making it work. That's easy (it becomes hard to cite a language that does not do it). It's about designing the language to interoperate with JS, and making that work. That is the real challenge.
It's very interesting that Scala and Scala.js have such a relatively painless interaction, but in general I'd say interoperation is "technically" simple by just employing an FFI?
Obviously, words like "seamless" and "effortless" start to enter the vocabulary here, but I'm not entirely these targets are worth it. Are they, do you think?
(I mean, obviously, Scala.js must have seamless 'interop' to Scala, but is 'seamless' introp with JS worth it, or should you require explicit FFI? I'm not sure, but I think you ultimately chose FFI-via-annotations, but there's a lot of fuzziness wrt. js.Dynamic.)
Don't you think that someone is eventually going to compile a JVM to wasm which would allow languages that compile to JVM bytecode to run directly as standard JVM bytecode in the browser? Wouldn't that allow to have as good performance as JS compilation? (I am asking you as it looks like you might have some expertise on languages that compile to both JVM and JS ;))
It might allow you to have as good performance as JS compilation, but definitely not as good interoperability with JS. Some of those languages, like ClojureScript, Scala.js and BuckleScript, have complete 2-way interop between them and JS, including for mutable objects, their properties and their methods.
"Just" compiling Scala to JVM-on-wasm does not give you the real power of Scala.js, which is its interoperability with JavaScript libraries. Similarly, just compiling Clojure to JVM-on-wasm does not give you the real power of ClojureScript.
People often forget about the interop with JS part--which is immensely more important than raw performance--if they don't actually work with a language that offers it. :-(
I don't know of anyone working on it, exactly because it is so difficult. So, while it might happen eventually, I don't think that anyone can provide an ETA at this stage.
Sure, why not? The difference is that WASM is aiming for near native performance of code, while the binary JS would still be limited to JS performance.
But that's what languages that compile to JavaScript support already today. The binary JS shouldn't prevent this behaviour if it is just a binary representation of a text version.
Yes, and for anything that already compiles to JS, adding this as an additional target shouldn't be too much work.
However, for anything that doesn't already compile to JS, this is essentially the same amount of work as targeting regular JavaScript. In that case, the work might be better spent making it compile to WASM. But, that's not a hard and fast rule, it really depends on the situation. And, of course, it could always target both.
It's a fairly simple optimization - it's still JavaScript, just compressed and somewhat pre-parsed.
The author of Smalltalk/X proposed this for Smalltalk at one of the Camp Smalltalk meetups about 17 years ago. Doing this for Javascript would also facilitate the running of other languages which use Javascript as a compiler target, providing 1st class debugging support for other languages as a side effect.
No link. We were all stuffed into a La Quinta Inn in San Diego, running ethernet between the balconies. There was just a bunch of us crowded into a motel room, and he just started talking about it.
Thank you for clarifying. Plain text source code is just not a good way to ship code. Browsers have a warm shared copy of a highly tuned VM. However to make use of it sites have to talk to it via plain text source code heavily penalizing startup.
A JS binary AST has the potential to transparently benefits all websites without any effort on their part if it's handled by a web server module, like GZIP, or a build step. This can remove redundant work that's done for billions of page load for all web sites.
Lua has something very similar(bytecode vs AST) via luac for a long while now. We've used to to speed up parse times in the past and it helps a ton in that area.
There's a problem---you can break out of Lua with malformed bytecode [1] and the Lua team don't want to spend the time trying to validate Lua byte code [2]. That's why the latest Lua version has an option to ignore precompiled Lua scripts.
Sure, if you're loading scripts from an untrusted source then don't use bytecode. They're pretty clear about that in the docs. However probably about 90% of Lua's use cases are embedded and so in that case it works just fine.
It faithfully models the original code. The idea is that if you want to transform `!0` to `true`, or if you want to obfuscate, etc. you can always plug an additional tool.
For the moment, it's JS + Rust, because Rust is better than JS when you keep refactoring Big Hairy Data Structures. However, once the data structures stabilize we're planning to shift it entirely to JS.
It seems this would break a number of libraries (can't name one, but certain I've seen it), although per the article it would be a simple affair for the browser to reify the encoded AST into a compatible representation, especially if comments are also eventually preserved (per article its on the roadmap)
I remember reading about some framework which was doing something nutty like embedding actual data in the comments on a function, and then parsing out those comments at run-time. For what it's worth, I believe it was on HN and in relation to the caveats for older V8 optimization w.r.t. function length (https://top.fse.guru/nodejs-a-quick-optimization-advice-7353...), but it was years ago so, as you say, hopefully they moved to something less insane in the intervening time.
Aside since you're here. The "Would it be possible to write a tool to convert serialized AST back to JS?" portion of the FAQ (https://github.com/syg/ecmascript-binary-ast#faq) says that it would be possible to generate source which would be "semantically equivalent" -- you might want to call out the Function.prototype.toString exception explicitly there, though admittedly that level of pedantry might be more obscuring than enlightening.
This is what BASIC interpreters on 8-bit systems did from the very beginning. Some BASIC interpreters did not even allow you to type the keywords. Storing a trivially serialized binary form of the source code is a painfully obvious way to reduce RAM usage and improve execution speed. You can also trivially produce the human-readable source back.
It's of course not compilation (though parsing is the first thing a compiler would do, too). It's not generation of machine code, or VM bytecode. it's mere compression.
This is great news because you got to see the source if you want, likely nicely formatted. You can also get rid of the minifiers, and thus likely see reasonable variable names in the debugger.
I am puzzled by how an binary AST makes the code significantly smaller than a minified+gziped version.
A JavaScript expression such as:
var mystuff = blah + 45
Gets minified as
var a=b+45
And then what is costly in there is the "var " and character overhead which you'd hope would be much reduced by compression.
The AST would replace the keywords by binary tokens, but then would still contain function names and so on.
I mean I appreciate the effort that shipping an AST will cut an awful lot of parsing, but I don't understand why it would make such a difference in size.
Afaik, improving parse time is the big goal here. Parsing is a significant stage of the compile pipeline, perf-wise. Some engines (Chakara at least), defer part of the parsing of the body of a function until the function itself is called, just to save precious milliseconds and not block the first render.
It's actually hard to get smaller than compressed minified JS. Source code is actually a very excellent high-level, compact representation of program text.
The space optimizations in BinaryJS are to get us back down to the point where we are as good or better than minified compressed JS.
The main goal is to allow for much faster parse times, but to do that without compromising other things like compressed source size.
The linked article somehow avoids ever stating the meaning of the acronym, and I had to Google it myself, so I imagine some other people might not know: AST stands for "abstract syntax tree".
One of my main concerns with this proposal, is the increasing complexity of what was once a very accessible web platform. You have this ever increasing tooling knowledge you need to develop, and with something like this it would certainly increase as "fast JS" would require you to know what a compiler is. Sure, a good counterpoint is that it may be incremental knowledge you can pick up, but I still think a no-work make everything faster solution would be better.
I believe there exists such a no-work alternative to the first-run problem, which I attempted to explain on Twitter, but its not really the greatest platform to do so, so I'll attempt to do so again here. Basically, given a script tag:
A browser, such as Chrome, would kick off two requests, one to abc.com/script.js, and another to cdn.chrome.com/sha256-123/abc.com/script.js. The second request is for a pre-compiled and cached version of the script (the binary ast). If it doesn't exist yet, the cdn itself will download it, compile it, and cache it. For everyone except the first person to ever load this script, the second request returns before the time it takes for the first to finish + parse. Basically, the FIRST person to ever see this script online, takes the hit for everyone, since it alerts the "compile server" of its existence, afterwards its cached forever and fast for every other visitor on the web (that uses chrome). (I have later expanded on this to have interesting security additions as well -- there's a way this can be done such that the browser does the first compile and saves an encrypted version on the chrome cdn, such that google never sees the initial script and only people with access to the initial script can decrypt it). To clarify, this solution addresses the exact same concerns as the binary AST issue. The pros to this approach in my opinion are:
1. No extra work on the side of the developer. All the benefits described in the above article are just free without any new tooling.
2. It might actually be FASTER than the above example, since cdn.chrome.com may be way faster than wherever the user is hosting their binary AST.
3. The cdn can initially use the same sort of binary AST as the "compile result", but this gives the browser flexibility to do a full compile to JIT code instead, allowing different browsers to test different levels of compiles to cache globally.
4. This would be an excellent way to generate lots of data before deciding to create another public facing technology people have to learn - real world results have proven to be hard to predict in JS performance.
5. Much less complex to do things like dynamically assembling scripts (like for dynamic loading of SPA pages) - since the user doesn't also have to put a binary ast compiler in their pipeline: you get binary-ification for free.
The main con is that it makes browser development even harder to break into, since if this is done right it would be a large competitive advantage and requires a browser vendor to now host a cdn essentially. I don't think this is that big a deal given how hard it already is to get a new browser out there, and the advantages from getting browsers to compete on compile targets makes up for it in my opinion.
I don't think the binary AST proposal changes the accessibility status quo. In my mind, the best analogy is to gzip, Brotli, etc.
If you had to have a complicated toolchain to produce gzipped output to get the performance boost, that would create a performance gap between beginners and more experienced developers.
But today, almost every CDN worth its salt will automatically gzip your content because it's a stateless, static transformation that can be done on-demand and is easily cached. I don't see how going from JavaScript -> binary AST is any different.
I actually think gzip serves as a good example of this issue: this comment alone is daunting to a beginner programmer and it really shouldn't. This chrome/cdn thing could ALSO be auto-gzipping for you so that a beginner throwing files on a random server wouldn't need to know whether it supports gzip or not. I think we really take for granted the amount of stuff completely unrelated to programming we've now had to learn. If our goal is to make the web fast by default, I think we should aim for solutions that work by default.
It's definitely the case that once a technology (such as gzip) gets popular enough it can get to "by default"-feeling status: express can auto-gzip, you can imagine express auto-binary-ast-ing. It's slightly more complicated because you still need to rely on convention of where the binary-ast lives if you want to get around the dual script tag issue for older browsers that don't support binary ast yet (or I suppose have a header that specifies it support binary ast results for js files?). Similarly, at some point CDN's may also do this for you, but this assumes you know what a CDN is and can afford one. The goal I'm after is it would be nice to have improvements that work by default on day 1, not after they've disseminated enough. Additionally, I think its really dangerous to create performance-targeted standards this high in the stack (gzip pretty much makes everything faster, binary ast one kind of file, and introduces a "third" script target of the browser). The chrome/cdn solution means that firefox/cdn might try caching at a different level of compilation, meaning we get actual real world comparisons for a year before settling on a standard (if necessary at all).
Edit: another thing to take into account, is that it now becomes very difficult to add new syntax features to JavaScript, if its no longer just the browser that needs to support it, but also the version of the Binary AST compiler than your CDN is using.
The process of getting content on to the web has historically been pretty daunting, and is IMO much easier now than the bad old days when a .com domain cost $99/year and hosting files involved figuring out how to use an FTP client.
In comparison, services like Now from Zeit, Netlify, Surge, heck, even RunKit, make this stuff so much easier in comparison now. As long as the performance optimizations are something that can happen automatically with tools like these, and are reasonable to use yourself even if you want to configure your own server, I think that's a net win.
I do agree with you though that we ought to fight tooth and nail to keep the web as approachable a platform for new developers as it was when we were new to it.
On balance, I'm more comfortable with services abstracting this stuff, since new developers are likely to use those services anyway. That's particularly true if the alternative is giving Google even more centralized power, and worse, access to more information that proxying all of those AST files would allow them to snoop on.
Interesting idea, which could be built on top of the Binary AST.
I would personally prefer it being handled transparently by the middleware or the cdn, which would neatly separate the responsibilities between the browser, the cache+compressor and the http server.
Anyway, one of the reasons this project is only about a file format is so that we can have this kind of conversation about what the browsers and other tools can do once we have with a compressed JS file.
One of my fears about doing this at the CDN level is that now introducing a new syntax feature means you need the browser to support it AND the version of the Binary AST compiler on your CDN. Imagine using a new JS keyword and all of a sudden all your code gets slower because its a syntax error at the CDN level. It would just slower the rate of introduction of new syntax features I think by needing a lot more coordination: its already a bit messy with different browsers having different support, now caniuse.com may need to include CDN's too.
This suggestion has a problem similar to the reason that browsers don't globally cache scripts based on integrity values: with your suggestion, if a domain temporarily hosts a .js file with a CSP-bypass vulnerability (ie. `eval(document.querySelector('.inline-javascript').textContent)` is a simple example; many popular javascript frameworks exist that do the equivalent of this), and then later removes it and starts using CSP, an attacker who knows an XSS vulnerability (which would otherwise be useless because of CSP) could inject a script tag with the integrity set equal to the CSP-vulnerable script that used to be hosted at the domain, and Chrome would find the script at the cdn.chrome.com cache.
(You might be thinking someone could set CSP to disable eval on their pages, but eval is reasonably safe even in the presence of otherwise-CSP-protected XSS attacks as long as you aren't using code that goes out of its way to eval things from the DOM, and it's more than annoying that the only way to protect yourself from this cache issue would be to disable eval. ... Also, there are some libraries that interpret script commands from the DOM without using eval, so disabling eval doesn't even protect you if you previously hosted one of those javascript files.)
You could have the cdn.chrome.com cache aggressively drop the cache of things greater than a certain amount of time like a day. But then there's a question of whether the requests to the cache are all just wasted bandwidth for the many requests by users to scripts that hadn't been loaded in a day. And the whole system means that website security can be dependent on cdn.chrome.com in some cases. I'd rather just build and host the processed binary AST myself. I already use a minifier; for most people, the binary AST tool would just replace their minifier.
This is reminiscent of the technique used by some versions of ETH Oberon to generate native code on module loading from a compressed encoding of the parse tree. Michael Franz described the technique as "Semantic-Dictionary Encoding":
«SDE is a dense representation. It encodes syntactically correct source program by a succession of indices into a semantic dictionary, which in turn contains the information necessary for generating native code. The dictionary itself is not part of the SDE representation, but is constructed dynamically during the translation of a source program to SDE form, and reconstructed before (or during) the decoding process. This method bears some resemblance to commonly used data compression schemes.»
This same technique also was used by JUICE, a short-lived browser plugin for running software written in Oberon in a browser. It was presented as an alternative to Java byte code that was both more compact and easier to generate reasonable native code for.
I seem to recall that the particular implementation was quite tied to the intermediate representation of the OP2 family of Oberon compilers making backward compatibility in the face of changes to the compiler challenging and I recall a conversation with someone hacking on Oberon that indicated that he'd chosen to address (trans)portable code by the simple expedient of just compressing the source and shipping that across the wire as the Oberon compiler was very fast even when just compiling from source.
I'm guessing the hard parts are:
(0) Support in enough browsers to make it worth using this format.
(1) Coming up with a binary format that's actually significantly faster to parse than plain text. (SDE managed this.)
(2) Designing the format to not be brittle in the face of change.
Indeed, one of the challenges was designing a format that will nicely support changes to the language. I believe that we have mostly succeeded there, and I'll blog about it once I find a little time. Now, of course, the next challenge is making sure that the file is still small enough even though we are using this future-proof format. We haven't measured this yet, but I expect that this will need additional work.
210 comments
[ 2.5 ms ] story [ 268 ms ] threadBy design of the first MVP iteration.
http://webassembly.org/roadmap/ and http://webassembly.org/docs/future-features/
GC (which is the main major feature required for JavaScript) is in progress, https://github.com/WebAssembly/design/issues/1079
So, your article is FUD in it's purest undistilled form.
The article is just reiterating an argument that Mozilla and Facebook made. If you’re saying Mozilla and Facebook are spreading Fear Uncertainty and Doubt with their proposal for a binary JS AST, then you may do so, but please realize that they probably had good reasons to start such a project.
EDIT: Even though I disagree with the parent, it is making some good points (specifically, that WebASM is going to add a GC), so flagging it to death doesn’t seem to be the right thing to do.
I'd like to see why it is good, given efforts with WebAsembly
Are you saying this comment is false?
> I am not aware of any project that achieves compilation of JavaScript to wasm
I.e., Javascript to WASM is on the roadmap and something we can use in the next few years? Or am I misunderstanding the situation?
As I mentioned in another conversation, if you feel you can contribute to Wasm and make it solve the problems we are solving here, this is great, by all means, please do so.
In the meantime, we are going to continue trying to solve some of the performance problems of the web using the techniques discussed in the blog entry because we are convinced that they are going to work better.
(I understand I could use elm, cjs, emscriptem or any other transpirer but I was thinking of ours spent around improving the js vm.
Behold one of the implementational details that emerged out of this language that was indeed "designed in 2 weeks":
https://tools.ietf.org/html/rfc4329: https://www.quirksmode.org/js/intro.html (from circa 2007, when it was trendy to NOT date webpages shakes fist):> JavaScript versions
> There have been several formal versions of JavaScript.
> 1.0: Netscape 2
> 1.1: Netscape 3 and Explorer 3 (the latter has bad JavaScript support, regardless of its version)
> 1.2: Early Version 4 browsers
> 1.3: Later Version 4 browsers and Version 5 browsers
> 1.4: Not used in browsers, only on Netscape servers
> 1.5: Current version.
> 2.0: Currently under development by Brendan Eich and others.
The link above points to a bit of interesting general discussion about versioning, and isn't as dense as the RFC.
It's one of several cases where backward compatibility on the web trumped cleaning up the language.
The more I see interpreted languages being compiled for speed purposes, and compiled languages being interpreted for ease-of-use purposes, desktop applications becoming subscription web applications (remember mainframe programs? ), and then web applications becoming desktop applications (electron) the more I realize that computing is closer to clothing fads than anything else. Can't wait to pickup some bellbottoms at my local target.
What happens a year from now when WebAssembl gets support for GC and modules?
You and your supporters consistently spread false information.
- WebAssembly does not support JS hence we need binary AST
WebAssembly is on track to support dynamic and GC-ed languages
- WebAssembly will be slower than binary AST
You've provided zero support for this statement. Meanwhile experiments with real apps (like Figma) show significant improvements with WebAssembly
- No one wants to ship bytecode
False
- it's hard to align browsers on bytecode
See WebAssembly
- you can't change bytecode once it's shipped
You can, eventually. Same argument can be applied to binary AST
- WebAssembly not supported by tools
Neither is binary AST. Meanwhile one of the goals of WebAssembly is tool support, readability etc.
There were other claims just as easily falsified, and yet dismissed out of hand.
So. What are you going to do with JS AST when WebAssembly gets support for JS?
You are obviously very passionate and I believe that nothing I can write will convince you, so I will not pursue this conversation with you after this post.
For the same reason, my answers here are for people who have not followed the original HN thread in which we have already had most of this conversation.
I also believe that the best way for you to demonstrate that another approach is better than the JavaScript Binary AST would be for you to work on demonstrating your approach, rather than criticizing this ongoing work.
> - WebAssembly does not support JS hence we need binary AST
> WebAssembly is on track to support dynamic and GC-ed languages
If/when WebAssembly gains the ability to interact with non-trivial JS objects, JS libraries, etc. we will be able to compare the WebAssembly approach with the Binary AST approach. GC support and dynamic dispatch are prerequisites but are not nearly sufficient to allow interaction with non-trivial JS objects and libraries.
So let's meet again and rediscuss this if/when this happens.
> - WebAssembly will be slower than binary AST
> You've provided zero support for this statement. Meanwhile experiments with real apps (like Figma) show significant improvements with WebAssembly
If you recall, we are only talking about loading speed. I believe that there is no disagreement on execution speed: once WebAssembly implementations are sufficiently optimized, it is very likely that well-tuned WebAssembly code will almost always beat well-tuned JS code on execution.
The argument exposed on the blog is that:
- attempting to compile JavaScript to existing WebAssembly is very hard (hard enough that nobody does it to the best of my knowledge);
- the specifications of JavaScript are complex enough that every single object access, every single array access, every single operator, etc. is actually a very complex operation, which often translates to hundreds of low-level opcodes. Consequently, should such a compilation take place, I suspect that this would considerably increase the size of the file and the parsing duration;
- by opposition, we have actual (preliminary) numbers showing that compressing to JavaScript Binary AST improves both file size and parse time.
While I may of course be wrong, the only way to be sure would be to actually develop such a compiler. I have no intention of doing so, as I am already working on what I feel is a more realistic solution, but if you wish to do so, or if you wish to point me to a project already doing so, I would be interested.
You refer to the experiments by Figma. While Figma has very encouraging numbers, I seem to recall that Figma measured the speedup of switching from asm.js to WebAssembly. In other words, they were measuring speedups for starting native code, rather than JS code. Also a valid experiment, but definitely not the same target.
> - No one wants to ship bytecode
> False
Are we talking about the same blog entry?
What I claimed is that if we ended up with one-bytecode-per-browser or worse, one-bytecode-per-browser-version, the web would be much worse than it is. I stand by that claim.
> - it's hard to align browsers on bytecode
> See WebAssembly
I wrote the following things:
- as far as I know, browser vendors are not working together on standardizing a bytecode for the JavaScript language;
- coming up with a bytecode for a language that keeps changing is really hard;
- keeping the language-as-bytecode and the language-as-interpreted in sync is really hard;
- because of the last two points, I do not think that anybody will start working on standardizing a bytecode for the JavaScript language.
In case of ambiguity, let me mention that I am part of these "browser vendors". I can, of course, be wrong, but once again, let's reconvene if/when this happens.
> - you can't change bytecode once it's shipped
> You can, eventually. Same a...
Interestingly enough, nowhere do you even mention these conversations in your attempts to push binary AST as hard as possible.
> Consequently, should such a compilation take place, I suspect that this would considerably increase the size of the file and the parsing duration;
Emphasis above is mine. However, it's presented (or was presented) by you as a fact.
> What I claimed is that if we ended up with one-bytecode-per-browser or worse, one-bytecode-per-browser-version, the web would be much worse than it is. I stand by that claim.
We are ending up with one wasm bytecode for every browser, aren't we?
> as far as I know, browser vendors are not working together on standardizing a bytecode for the JavaScript language;
Because they are working together on standardizing bytecode for the web in general, aren't they?
> coming up with a bytecode for a language that keeps changing is really hard
So you're trying to come up with a binary AST for a language that keeps changing :-\
> keeping the language-as-bytecode and the language-as-interpreted in sync is really hard
What's the point of WebAssembly then?
> I do not think that anybody will start working on standardizing a bytecode for the JavaScript language.
Because that's not really required, is it? This is a non-goal, and never was the goal. The goal is to create an interoperable standardized bytecode (akin to JVM's bytecode or .Net's MSIL), not a "standardized bytecode for Javascript". For some reason you don't even want to mention this.
> I claimed that no browser vendor seriously contemplates exposing their internal bytecode format
They don't need to.
> Additionally, the JavaScript Binary AST is designed in such a manner that evolutions of the JavaScript language should not break existing parsers.
I shudder to think how rapidly changing languages like Scala, ClojureScript etc. can ever survive on the JVM. The horror!
> If/when that day arrives, I'll compare both approaches.
Basically you will end up with two representations of JS: a binary AST and a version that compiles to WASM. Oh joy. Wasn't this something you wanted to avoid?
Combined with the fact, as mentioned above, that DOM access is significantly slower means that WASM isn't a suitable candidate. This is something you forgot to mention or take into account in your comment, for some reason.
Yes this does seem to overlap a bit with wasm as you have noted, but saying "well we could get this optimization but we need to wait several years until this highy complex other spec is completely finished" doesn't seem as good.
Why not do this, and use wasm when it's available? Why can't you have both?
As opposed to Binary AST which as available now? :)
> Combined with the fact, as mentioned above, that DOM access is significantly slower
Given that DOM access for WASM currently happens via weird interop through JavaScript (if I'm not mistaken) how is this a fact?
> "well we could get this optimization but we need to wait several years until this highy complex other spec is completely finished" doesn't seem as good.
No. My point is: "Let's for once make a thing that is properly implemented, and not do a right here right now short-sighted short-range solution"
That's basically how TC39 committee operates these days: if something is too difficult to spec/design properly, all work is stopped and half-baked solutions are thrown in "because we need something right now".
> Why not do this, and use wasm when it's available? Why can't you have both?
Because this means:
- spreading the resources too thin. There is a limited amount of people who can do this work
- doing much of the work twice
- JS VM implementors will have to support text-based parsing (for older browsers), new binary AST and WASM
... because DOM access is significantly (10x) slower? That alone rules out your approach right now, regardless of the other points raised.
> Because this means: ...
When you understand how weak these arguments are you will understand the negative reaction to your comments on this issue.
You're clearly very passionate about this issue but you don't seem to be assessing the trade offs. Having something right now and iterating on it is better than waiting an indeterminate amount of time for a possible future solution involving an overlapping but otherwise unrelated specification that has not been fully implemented by anyone to a satisfactory point, and one with very complex technical issues blocking its suitability.
Sure, it would be nice to use WASM for this, but it is in no way needed at all. Given the status of WASM and the technical issues present with using it in this way it is odd to champion it to such a degree.
It seems your entire arguments boil down to "WASM may be OK to use at some point in the future, stop working on this and wait!". I, and I'm assuming others, don't see this as a very convincing point.
If I may, I'd offer some advice: stop taking this issue to heart. Time will tell if you're right, and making borderline insulting comments to the technical lead of the project in an attempt to push your position doesn't help anyone.
The world is heating up and species are dying, there are much better causes to take to heart.
It is, but there's several roadmap items that would need to be ticked off for it to run well. Aside from GC, you would probably need:
- Direct DOM access. The current way of interacting with the DOM from WASM is, at best, 10x slower.
- JIT underpinnings, like a polymorphic inline cache[1]
[1]https://github.com/WebAssembly/design/blob/master/FutureFeat...
It's not clear how far off those things might be.
The binary AST is a quick win for brownfield technology, with already a working version in an experimental Firefox build. It can be rolled quite fast. It improves right now the experience of many users on existing codebase the same way minification did. And improve the experience of current web assembly, as it is still largely dependent on the speed of JS. I'll take this feature any day.
To be fair, these two concepts are similar and I may be totally misunderstanding what this project is about. In the spirit of fairness, let me test my understanding. You are saying wasm bytecode is one step too early and a true "machine code" format would be better able to improve performance (especially startup time). I'm not following wasm development, but from comments here I am gathering that wasm is too level and you want something that works on V8. Is that what this project is about?
On a side note, it's truly a testament to human nature that the minute we get close to standardizing on something (wasm), someone's gotta step up with another approach.
> If you prefer, this Binary AST representation is a form of source compression, designed specifically for JavaScript, and optimized to improve parsing speed.
I am not sure but there may be a misunderstanding on the word "binary". While the word "binary" is often used to mean "native", this is not the case here. Here, "binary" simply means "not text", just as for instance images or zipped files are binary.
A compiler typically goes from a high-level language to a lower-level language, losing data. I prefer calling this a compression mechanism, insofar as you can decompress without loss (well, minus layout and possibly comments). Think of it as the PNG of JS: yes, you need to read the source code/image before you can compress it, but the output is still the same source code/image, just in a different format.
> You are saying wasm bytecode is one step too early and a true "machine code" format would be better able to improve performance (especially startup time). I'm not following wasm development, but from comments here I am gathering that wasm is too level and you want something that works on V8. Is that what this project is about?
No native code involved in this proposal. Wasm is about native code. JS BinAST is about compressing your everyday JS code. As someone pointed out in a comment, this could happen transparently, as a module of your HTTP server.
> On a side note, it's truly a testament to human nature that the minute we get close to standardizing on something (wasm), someone's gotta step up with another approach.
Well, we're trying to solve a different problem :)
When I first discovered what Yoric and syg were doing, the first thing that I thought of was old-school Visual Basic. IIRC when you saved your source code from the VB IDE, the saved file was not text: it was a binary AST.
When you reopened the file in the VB6 IDE, the code was restored to text exactly the way that you had originally written it.
VB6 projects were actually a textual format - even the widget layout: https://msdn.microsoft.com/en-us/library/aa241723(v=vs.60).a...
As someone who runs a WYSIWYG app builder startup (https://anvil.works), I can attest that this is a Really Good Idea for debugging your IDE.
If it's not text, then what is it? I'm not sure "not text" is a good definition of the word "binary".
> A compiler typically goes from a high-level language to a lower-level language, losing data.
I don't agree, I don't think there is any loss in data, the compiled-to representation should cover everything you wanted to do (I suppose not counting tree-shaking or comment removal).
> I prefer calling this a compression mechanism, insofar as you can decompress without loss (well, minus layout and possibly comments).
Ahh, so you mean without losing the original textual representation of the source file.
> Wasm is about native code
Here you are making claims about their project that are just not the whole picture. Here's the one-line vision from their homepage[1]:
> WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web.
With that description in mind, how do you see BinAST as different?
> Well, we're trying to solve a different problem :)
I think you might be misunderstanding what wasm is intended for. Here's a blurb from the wasm docs that is pertinent:
> A JavaScript API is provided which allows JavaScript to compile WebAssembly modules, perform limited reflection on compiled modules, store and retrieve compiled modules from offline storage, instantiate compiled modules with JavaScript imports, call the exported functions of instantiated modules, alias the exported memory of instantiated modules, etc.
The main difference I can gather is that you are intending BinAST to allow better reflection on compiled modules than wasm intends to support.
Here's another excerpt from their docs (and others have mentioned this elsewhere):
> Once GC is supported, WebAssembly code would be able to reference and access JavaScript, DOM, and general WebIDL-defined objects.
[1]: http://webassembly.org/
[META: Wow, I thought downvotes were for negative or offtopic comments]
I ran a google search for "js to wasm" and found a ticket on the webassembly github that explained it all: https://github.com/WebAssembly/design/issues/219
Compilation maps a program in a higher level language to a program in a lower level language. The map is not required to be one-to-one: the colloquial term for this is "lossy."
Parsing is unavoidable, regardless if the code is interpreted or compiled. This proposal seems to further compress the AST somehow.
Basically the idea is to already preprocess the text source, so that the client can skip two steps on execution: lexical analysis and the parsing of the text source resulting in the AST. The post explains why the authors believe that this is a good idea.
Compiled C is not going to go away any sooner than interpreted Javascript - but a widening of the options available is great as it allows us to focus on developing things quickly and correctly, rather than making decisions based on which particular annoyance you're happy to put up with.
Maybe they think there is a One True Way. Maybe they think every building needs to be reinforced concrete and structural steel, now and forever, in every possible context.
I was using Smalltalk on some university projects, before Sun decided to rename Oak and announce Java to the world.
The development experience was quite good.
Similarly with Native Oberon, which captured many of the Mesa/Cedar workflows.
That would have been very interesting. I liked Dart from the brief time I looked at it. The web still feels like a somewhat crippled platform to develop for.
Which is why nowadays I always favour native development when given the option, in spite of having been a Web 1.0 enthusiastic developer.
They have an "intermediate code" that they somewhat compile down to. But this is really a more compact version of the source than a binary though. You can see this easily by running a decompiler. Often times the decompiled IL is almost identical to the source. And before the JIT kicks in the IL is typically interpreted.
You get the best of both worlds. Easy to compile, easy to decompile, platform agnostic, compact code, and fast if it needs to be
It is either AOT compiled to native code via NGEN, Mono AOT, MDIL or .NET Native.
Or JITed on file load before actually executing the code.
The only .NET toolchain, from Microsoft, that actually does interpret IL it is .NET Micro Framework.
The idea of using bytecodes as portable execution formats goes back to mainframes, of which IBM AS/400's TIMI is the best known example.
Which actually can be configured to always JIT as well.
The majority of JVMs have a non-standard flag that allows to configure how the interpreter, JIT or if supported AOT compiler work together.
I think there are two main drivers for fad-ism in software. One is we as developers, are required to chase the popular languages and frameworks to stay current, marketable, and employable. So there is always a sense of "what do I have to learn next, so I can switch jobs succesfully when I need to". Another driver is, developers seek to gain experience by re-doing things from the past. Example, creating new languages, or compiler for an existing language, provides inexperience developers with fantastic new experiences and knowledge. This is desirable.
So yeah, we got fads, and us old timers, or not so old timers with a historical perspective, watch our lawns, but everyone has to learn somehow. Ideally a lot of this would come from an apprenticeship/journeyman system, or a University degree of some sort. But for now it's all we have.
There's a lot of pressure to be part of a popular tribe, and so you see situations where even a mild criticism of, for example, the a piece of the JavaScript tribe's technology (like, say, npm or Webpack) tends to elicit vitriolic responses and counter arguments.
You can sometimes get away with this kind of criticism if you choose your words carefully and make it very clear (or at least pretend to) that you're actually a member of the tribe you're criticizing, and that your criticism is meant to be constructive. So you say something like 'I use npm, and I like it, but here's where I struggle with it and here's how I'd improve it'. But if you just write about why you dislike it, you're likely to be flamed and criticized, even if everything you wrote verifiably correct.
So I find that watching programmers argue in blogs and on HN and Reddit feels a lot like reading political arguments on Reddit, or Facebook. And maybe that's why programming tends to be faddish. Each tribe is mostly only aware of its own history; there's no real shared sense of culture, or much awareness of the rich shared history that got us to where we are today. And so you see lots of wheel reinvention, as people poorly re-solve problems that were already solved long ago by other programming tribes.
These are just my personal observations, though. I could very well be completely wrong. :)
I think a much better approach to this pronblem would be a compression format that's designed specifically for JavaScript. It could still be negotiable, like GZIP, so anyone wanting to see the source would be able to see it. It could also be designed in a way that allows direct parsing without (full?) decompression.
We are not working on the negotiation part for the moment, because that's not part of the JS VM, but this will happen eventually.
I'm one of those developers who couldn't care less about the 'open nature of the web'. I understood the necessity of it to the early, emerging internet, but times have changed. Now that we have secure sandboxes and the web is choking on its own bloat, it's time to shift back to binary blobs.
[1]: Except maybe Silverlight. From what I remember, it didn't see enough success to be a tempting target for hackers.
I wouldn't call this "compiled JavaScript". In broad strokes what's happening is you take the result of parsing JavaScript source to an AST and serialize that; then next time you deserialize the AST and can skip the parsing stage.
(Source: I spent a summer working on JS engine and JIT performance at Mozilla.)
Instead, I think the point was that Javascript is a fad (we'll see whether this is true by watching how popular compile-to-WASM languages become compared to JS, once WASM becomes widespread and stable).
Alternatively, we might say that JS was created (in 10 days, yadda yadda) at a time when the fads were dynamic typing over static typing; interpreters over compilers; GC over manual or static memory management; OOP over, say, module systems; imperative over logic/relational/rewriting/etc.; and so on. JS's role as the Web language has tied developers' hands w.r.t. these tradeoffs for 20 years; long enough that a significant chunk of the developer population hasn't experienced anything else, and may not really be aware of some of these tradeoffs; some devs may have more varied experience, but have developed Stockholm Syndrome to combat their nostalgia ;)
As an example, one of the benefits of an interpreter is that it can run human-readable code; this is a sensible choice for JS since it fits nicely with the "View Source" nature of the Web, but it comes at a cost of code size and startup latency. The invention of JS obfuscation and minifiers shows us that many devs would prefer to pick a different balance between readability and code size than Eich made in the 90s. This project brings the same option w.r.t. startup latency. WASM opens up a whole lot more of these tradeoffs to developers.
For that use a forgiving scripting language is a good fit. What changed is what javascript, and the web, is used for. Embedded Java and Flash showed that there was an appetite for the web to do more and the security problems involved with those technologies showed they weren't a good fit.
Javascript was adapted to fill that void by default as it was the only language that every browser could agree on using.
At each step developers are trying to create the best thing they can with the tools at their disposal. There will always be a tradeoff between flexibility and ease of use. There's a reason Electron exists — the browser has limitations that are easier to work around in Electron. There's a reason we moved to putting stuff online, we could write it once and distribute it everywhere.
Well, yeah. The point is that we don't have a consistent definition of "best" that's constant over time. Only by changing your direction all the time can you end up walking in circles.
In the last 25 years or so, we actually got something like a pop culture, similar to what happened when television came on the scene and some of its inventors thought it would be a way of getting Shakespeare to the masses. But they forgot that you have to be more sophisticated and have more perspective to understand Shakespeare. What television was able to do was to capture people as they were.
So I think the lack of a real computer science today, and the lack of real software engineering today, is partly due to this pop culture.
...
I don’t spend time complaining about this stuff, because what happened in the last 20 years is quite normal, even though it was unfortunate. Once you have something that grows faster than education grows, you’re always going to get a pop culture.
...
But pop culture holds a disdain for history. Pop culture is all about identity and feeling like you're participating. It has nothing to do with cooperation, the past or the future — it's living in the present. I think the same is true of most people who write code for money. They have no idea where [their culture came from] — and the Internet was done so well that most people think of it as a natural resource like the Pacific Ocean, rather than something that was man-made. When was the last time a technology with a scale like that was so error-free? The Web, in comparison, is a joke. The Web was done by amateurs.
sources:
http://queue.acm.org/detail.cfm?id=1039523
http://www.drdobbs.com/architecture-and-design/interview-wit...
The downside is that exposure to both of those led me to write some software in both Smalltalk and Common Lisp...which is a downside because having worked with those makes some currently popular tools seem like dirty hacks.
Although I use things and enjoy things like React, and Webpack, and npm and I'm very happy with the things I'm able to create with them, when I stop and think about it, the tooling and building/debugging workflow feels pretty disjointed to what was available in Smalltalk and CL environments 30 years ago.
I understand why those tools didn't win over the hearts and minds of developers at the time. They were expensive and not that easily accessible to the average developer. I just wish that as an industry, we'd at least have taken the time to understand what they did well and incorporate more of those lessons into our modern tools.
You develop one app, and it can run as both web and desktop application, or even on mobile with some extra efforts.
Say you want to quickly edit something like a document, you don't need to install Word, just open browser and load Google Docs or Office 365.
And if you find yourself constantly using one web app or website (travis CI, Trello), you can wrap it with nativefier [1] and use it as a desktop app.
[1] https://github.com/jiahaog/nativefier
Compilation and interpretation both have distinct advantages. It's hard to do both (read: it took a while) and each has tradeoffs.
I'm impressed and grateful that I can get compile time errors for interpreted languages, and I'd feel the same about being able to use a compiled lang in a repl.
Regarding the actual topic at hand, this isn't compiled JavaScript, just parsed JavaScript. They're shipping an AST, not bytecode/machine code.
We'll only know for sure once we can start testing in real conditions, though.
If you wish to follow the development of the reference implementation, you can find it here: https://github.com/Yoric/binjs-ref/ . It's very early and the format will change often as we
1/ fix bugs;
2/ remove debugging info;
3/ start working seriously on compression;
4/ optimize.
> So, a joint team from Mozilla and Facebook decided to get started working on a novel mechanism that we believe can dramatically improve the speed at which an application can start executing its JavaScript: the Binary AST.
I really like the organization of the present article, the author really answered all the questions I had, in an orderly manner. I'll use this format as a template for my own writing. Thanks!
Personally, I don't see the appeal for such a thing, and seems unlikely all browsers would implement it. It will be interesting to see how it works out.
> All they have to do is convince Google. Chrome's the king of the castle right now.
When I replied "Native Client", I was giving an example where Chrome came out with something the other browser vendors rejected on technical grounds.
I love this development (Binary AST) and hope it's adopted.
Facebook can just run a feature detection JS snippet to see if your browser supports the Binary AST, and select the URLs of the other JS assets accordingly. If Binary AST is a thing, I can easily see web frameworks implementing such a format selection transparently.
And hey, if it contributes to people perceiving Firefox as faster than Chrome, I'm all for it. :)
It's going through TC39 (the committee that decides how the JavaScript language should evolve) and recently reached stage 1 (proposals advance from stage 0 to stage 4). I believe that if it reaches stage 4, then that means that all browser vendors have agreed to implement it, so it certainly seems to be their goal.
At a personal level, I feel pretty confident that BinaryJS will help your case. The theory behind the gains was pretty solid before we designed the prototype. The prototype, for me, basically proved the theory.
My personal hope is that by the time we're done squeezing all we can out of this - which includes zero-costing lazy function parsing, and on-line bytecode generation, we can cut the "prepare for execution" time by 80%.
Some context:
https://v8project.blogspot.com/2017/05/energizing-atom-with-...
https://github.com/nodejs/node/issues/13877
It's a fairly simple optimization - it's still JavaScript, just compressed and somewhat pre-parsed.
WASM doesn't currently have built-in garbage collection, so to use it to compress/speed up/whatever JavaScript, you would have to compile an entire JavaScript Virtual Machine into WASM, which is almost certainly going to be slower than just running regular JavaScript in the browser's built-in JS engine.
(This is true for the time being, anyway. WASM should eventually support GC at which point it might make sense to compile JS to WASM in some cases.)
What's proposed is structural compression of JS with JS-specific bits to speed things up even more. What's proposed is not compiled JS, in that the original JS is not meaningfully transformed at all. There is a very explicit design goal to retain the original syntactic structure.
OTOH WebAssembly is like a new low-level ISA accessible from web browsers. To use wasm, one does have to compile to it. As the parent here says, compiling JS -> wasm currently requires at least a GC but also much more. To engineer a performant VM and runtime for a dynamic programming language like JS is a time-consuming thing. It is curious to see so many folks think that JS can straightforwardly be compiled to wasm. Currently wasm and JS serve very different needs; and I also don't think JS will be going anywhere for many, many years.
Edit: formatting
However, all these languages can benefit from the Binary AST right away. Just like any codebase directly written in JavaScript. If the Binary AST has some decent story about position mapping (see [1] which I just filed), they might even get somewhat better tooling/debugging support going through the Binary AST than going through .js source files, out of the box.
[1] https://github.com/syg/ecmascript-binary-ast/issues/17
If you have ideas and/or spare cycles, of course, they are welcome :)
As a side-note: I believe that we could build upon the (very early) proposed mechanism for comments to also store positions. Size-optimized BinAST files would drop both comments and positions, while debugging-optimized BinAST files would keep both at the end of the file so as to not slow down parsing until they are needed.
If you can point me to the best place to suggest ideas or spend my spare cycles, I would gladly do so. At the very least, I can comment on how we serialize positions in the (tree-based) Scala.js IR, which is size-optimized.
Of course, as you just both said, your work is kind of complementary... which is always nice. :)
Anyway, thanks for the long-term thinking to the both of you.
I do recognize that this is a side point, but I think it's worth mentioning.
That's very hard (if not impossible) to achieve without leak and performance degradation if the two languages have their own GC, with their own heaps.
Compiling a language to JS is not about making it work. That's easy (it becomes hard to cite a language that does not do it). It's about designing the language to interoperate with JS, and making that work. That is the real challenge.
It's very interesting that Scala and Scala.js have such a relatively painless interaction, but in general I'd say interoperation is "technically" simple by just employing an FFI?
Obviously, words like "seamless" and "effortless" start to enter the vocabulary here, but I'm not entirely these targets are worth it. Are they, do you think?
(I mean, obviously, Scala.js must have seamless 'interop' to Scala, but is 'seamless' introp with JS worth it, or should you require explicit FFI? I'm not sure, but I think you ultimately chose FFI-via-annotations, but there's a lot of fuzziness wrt. js.Dynamic.)
"Just" compiling Scala to JVM-on-wasm does not give you the real power of Scala.js, which is its interoperability with JavaScript libraries. Similarly, just compiling Clojure to JVM-on-wasm does not give you the real power of ClojureScript.
People often forget about the interop with JS part--which is immensely more important than raw performance--if they don't actually work with a language that offers it. :-(
Because, surprise, it's an MVP, and wok has already started to bring other languages (including JavaScript) to it.
So. The question is: one-two years from now, when there's support for wasm in javascript, where does it leave binary AST?
How likely is this to happen in the next 2 years? I thought it'd be a lot more difficult.
However, for anything that doesn't already compile to JS, this is essentially the same amount of work as targeting regular JavaScript. In that case, the work might be better spent making it compile to WASM. But, that's not a hard and fast rule, it really depends on the situation. And, of course, it could always target both.
The author of Smalltalk/X proposed this for Smalltalk at one of the Camp Smalltalk meetups about 17 years ago. Doing this for Javascript would also facilitate the running of other languages which use Javascript as a compiler target, providing 1st class debugging support for other languages as a side effect.
A JS binary AST has the potential to transparently benefits all websites without any effort on their part if it's handled by a web server module, like GZIP, or a build step. This can remove redundant work that's done for billions of page load for all web sites.
And sadly, I can see the same happening here.
[1] https://www.corsix.org/content/malicious-luajit-bytecode
[2] The overhead will eat any performance gained by using precompiled Lua code in the first place.
As usual, read these numbers with a pinch of salt, they are bound to change many times before we are done.
The BinJS prototype will be written in pure javascript I assume to speed its adoption?
> This method would return something like "[sourceless code]".
If you do find one, please feel free to add a comment on the blog or one of the trackers :)
Aside since you're here. The "Would it be possible to write a tool to convert serialized AST back to JS?" portion of the FAQ (https://github.com/syg/ecmascript-binary-ast#faq) says that it would be possible to generate source which would be "semantically equivalent" -- you might want to call out the Function.prototype.toString exception explicitly there, though admittedly that level of pedantry might be more obscuring than enlightening.
It's of course not compilation (though parsing is the first thing a compiler would do, too). It's not generation of machine code, or VM bytecode. it's mere compression.
This is great news because you got to see the source if you want, likely nicely formatted. You can also get rid of the minifiers, and thus likely see reasonable variable names in the debugger.
A JavaScript expression such as:
var mystuff = blah + 45
Gets minified as var a=b+45
And then what is costly in there is the "var " and character overhead which you'd hope would be much reduced by compression.
The AST would replace the keywords by binary tokens, but then would still contain function names and so on.
I mean I appreciate the effort that shipping an AST will cut an awful lot of parsing, but I don't understand why it would make such a difference in size.
Can someone comment?
https://news.ycombinator.com/item?id=15046750
The space optimizations in BinaryJS are to get us back down to the point where we are as good or better than minified compressed JS.
The main goal is to allow for much faster parse times, but to do that without compromising other things like compressed source size.
"I kinda think that there were no front-end languages actually. It's kinda all about web platform & browsers can't do things out of the box."
"Graphic interface shouldn't execute program on its own rather than rendering string on _platform_ which won't bother more."
"This is partly why people delegate js rendering to server. At the end of the day all script should be just WebAssembly bytecodes sent down."
"Browser should act as physical rendering object like pure monitor screen. User shouldn't have to inspect photon or write photon generators."
"SPA or PWA is just that about network request reduction, and how much string wanted to send at a time & today http/2 can help that a lot."
"Project like Drab https://github.com/grych/drab 's been doing quite well to move computation back to "server" (opposite to self-service client)"
"WebAssembly compromise (to complement js) to implement the platform. JS api and WebAssembly should be merged or united."
"VirtualDom as if it is a right way should be built-in just like DOM get constructed from html _string_ from server. All JS works must die."
"That's how WebComponent went almost a half way of fulfilling web platform. It is unfortunate js has gone far, tools are actively building on"
"I'd end this now before some thought of individualism-ruining-the-platform take over. That's not gonna be something i'd like to write (now)"
-----
Not a complete version though. Kind of general speaking but I've been thinking in detail a bit. Then hours later I found this thread.
https://en.wikipedia.org/wiki/Abstract_syntax_tree
I believe there exists such a no-work alternative to the first-run problem, which I attempted to explain on Twitter, but its not really the greatest platform to do so, so I'll attempt to do so again here. Basically, given a script tag:
A browser, such as Chrome, would kick off two requests, one to abc.com/script.js, and another to cdn.chrome.com/sha256-123/abc.com/script.js. The second request is for a pre-compiled and cached version of the script (the binary ast). If it doesn't exist yet, the cdn itself will download it, compile it, and cache it. For everyone except the first person to ever load this script, the second request returns before the time it takes for the first to finish + parse. Basically, the FIRST person to ever see this script online, takes the hit for everyone, since it alerts the "compile server" of its existence, afterwards its cached forever and fast for every other visitor on the web (that uses chrome). (I have later expanded on this to have interesting security additions as well -- there's a way this can be done such that the browser does the first compile and saves an encrypted version on the chrome cdn, such that google never sees the initial script and only people with access to the initial script can decrypt it). To clarify, this solution addresses the exact same concerns as the binary AST issue. The pros to this approach in my opinion are:1. No extra work on the side of the developer. All the benefits described in the above article are just free without any new tooling.
2. It might actually be FASTER than the above example, since cdn.chrome.com may be way faster than wherever the user is hosting their binary AST.
3. The cdn can initially use the same sort of binary AST as the "compile result", but this gives the browser flexibility to do a full compile to JIT code instead, allowing different browsers to test different levels of compiles to cache globally.
4. This would be an excellent way to generate lots of data before deciding to create another public facing technology people have to learn - real world results have proven to be hard to predict in JS performance.
5. Much less complex to do things like dynamically assembling scripts (like for dynamic loading of SPA pages) - since the user doesn't also have to put a binary ast compiler in their pipeline: you get binary-ification for free.
The main con is that it makes browser development even harder to break into, since if this is done right it would be a large competitive advantage and requires a browser vendor to now host a cdn essentially. I don't think this is that big a deal given how hard it already is to get a new browser out there, and the advantages from getting browsers to compete on compile targets makes up for it in my opinion.
If you had to have a complicated toolchain to produce gzipped output to get the performance boost, that would create a performance gap between beginners and more experienced developers.
But today, almost every CDN worth its salt will automatically gzip your content because it's a stateless, static transformation that can be done on-demand and is easily cached. I don't see how going from JavaScript -> binary AST is any different.
It's definitely the case that once a technology (such as gzip) gets popular enough it can get to "by default"-feeling status: express can auto-gzip, you can imagine express auto-binary-ast-ing. It's slightly more complicated because you still need to rely on convention of where the binary-ast lives if you want to get around the dual script tag issue for older browsers that don't support binary ast yet (or I suppose have a header that specifies it support binary ast results for js files?). Similarly, at some point CDN's may also do this for you, but this assumes you know what a CDN is and can afford one. The goal I'm after is it would be nice to have improvements that work by default on day 1, not after they've disseminated enough. Additionally, I think its really dangerous to create performance-targeted standards this high in the stack (gzip pretty much makes everything faster, binary ast one kind of file, and introduces a "third" script target of the browser). The chrome/cdn solution means that firefox/cdn might try caching at a different level of compilation, meaning we get actual real world comparisons for a year before settling on a standard (if necessary at all).
Edit: another thing to take into account, is that it now becomes very difficult to add new syntax features to JavaScript, if its no longer just the browser that needs to support it, but also the version of the Binary AST compiler than your CDN is using.
In comparison, services like Now from Zeit, Netlify, Surge, heck, even RunKit, make this stuff so much easier in comparison now. As long as the performance optimizations are something that can happen automatically with tools like these, and are reasonable to use yourself even if you want to configure your own server, I think that's a net win.
I do agree with you though that we ought to fight tooth and nail to keep the web as approachable a platform for new developers as it was when we were new to it.
On balance, I'm more comfortable with services abstracting this stuff, since new developers are likely to use those services anyway. That's particularly true if the alternative is giving Google even more centralized power, and worse, access to more information that proxying all of those AST files would allow them to snoop on.
I would personally prefer it being handled transparently by the middleware or the cdn, which would neatly separate the responsibilities between the browser, the cache+compressor and the http server.
Anyway, one of the reasons this project is only about a file format is so that we can have this kind of conversation about what the browsers and other tools can do once we have with a compressed JS file.
(You might be thinking someone could set CSP to disable eval on their pages, but eval is reasonably safe even in the presence of otherwise-CSP-protected XSS attacks as long as you aren't using code that goes out of its way to eval things from the DOM, and it's more than annoying that the only way to protect yourself from this cache issue would be to disable eval. ... Also, there are some libraries that interpret script commands from the DOM without using eval, so disabling eval doesn't even protect you if you previously hosted one of those javascript files.)
You could have the cdn.chrome.com cache aggressively drop the cache of things greater than a certain amount of time like a day. But then there's a question of whether the requests to the cache are all just wasted bandwidth for the many requests by users to scripts that hadn't been loaded in a day. And the whole system means that website security can be dependent on cdn.chrome.com in some cases. I'd rather just build and host the processed binary AST myself. I already use a minifier; for most people, the binary AST tool would just replace their minifier.
«SDE is a dense representation. It encodes syntactically correct source program by a succession of indices into a semantic dictionary, which in turn contains the information necessary for generating native code. The dictionary itself is not part of the SDE representation, but is constructed dynamically during the translation of a source program to SDE form, and reconstructed before (or during) the decoding process. This method bears some resemblance to commonly used data compression schemes.»
See also "Code-Generation On-the-Fly: A Key to Portable Software" https://pdfs.semanticscholar.org/6acf/85e7e8eab7c9089ca1ff24...
This same technique also was used by JUICE, a short-lived browser plugin for running software written in Oberon in a browser. It was presented as an alternative to Java byte code that was both more compact and easier to generate reasonable native code for.
https://github.com/Spirit-of-Oberon/Juice/blob/master/JUICE....
I seem to recall that the particular implementation was quite tied to the intermediate representation of the OP2 family of Oberon compilers making backward compatibility in the face of changes to the compiler challenging and I recall a conversation with someone hacking on Oberon that indicated that he'd chosen to address (trans)portable code by the simple expedient of just compressing the source and shipping that across the wire as the Oberon compiler was very fast even when just compiling from source.
I'm guessing the hard parts are: (0) Support in enough browsers to make it worth using this format. (1) Coming up with a binary format that's actually significantly faster to parse than plain text. (SDE managed this.) (2) Designing the format to not be brittle in the face of change.
Indeed, one of the challenges was designing a format that will nicely support changes to the language. I believe that we have mostly succeeded there, and I'll blog about it once I find a little time. Now, of course, the next challenge is making sure that the file is still small enough even though we are using this future-proof format. We haven't measured this yet, but I expect that this will need additional work.