With regards to porffor. It's a very good project and people behind it are probably much better at writing interpreters/compilers, but the biggest difference is in what WASM features the projects use. porffor uses only core WASM, which means they have to implement a lot more features themselves. Data types like arrays, structs/objects, garbage collection, exception handling etc. I am using WASM features added in proposals standardized very recently, like WASM GC or exception handling, which means I get a lot of the features almost for free. And I suppose that's also why semantics like scopes/closures are really hard to do for projects like porffor or even AssemblyScript and were relatively easy in Jaws.
The trade off is mainly in support. porffor compiled binaries can run on a lot of different WASM runtimes, I think there are even some runtimes for Core WASM for embedded devices. In case of Jaws, the runtime needs to support the proposals I use. Currently there are only two runtimes, that I know of, supporting both WASM GC and exception handling: V8 and WasmEdge. I believe more runtimes will get there, like for example WasmTime people are working towards exception handling, but it will take some time. Which is not a problem for me, cause it will definitely take a bit to reach any production level JS compatibility - I think the runtimes will have time to catch up with the proposals by then.
https://github.com/web-devkits/Wasmnizer-ts
How does Jaws compare to that?
The main difference is obviously TypeScript vs JavaScript. Because they are not bothering with JavaScript, some stuff is much easier, like for example if a function specifies an argument as `number`, you can statically compile it to use a type representing a number (possibly even without heap allocations) instead of passing something like `anyref` everywhere and doing typechecks.
The second big difference is that they seem to use types imported form the host. This means they can implement part of the types/builtins/methods on the host (which is easier, cause in JavaScript you simply use JavaScript for defining host stuff) at a cost of doing more calls from WASM to the host. And then you need the host to implement those functions (here is an example for JS host: https://github.com/web-devkits/Wasmnizer-ts/blob/main/tools/...). My plan for Jaws is to only rely on WASI, so that you can run your program on any runtime that supports WASI.
I'm also not sure about their approach to semantics. I can't quite grasp how they implement for example scopes. I tried to compile a small TS script that relies on scope, like:
let message: string = 'Hello, World!';
function test() {
console.log(message);
}
test()
And the result was console.log printing null. I'm not sure if I'm doing something wrong or is it expected, but I'll ask them in an issue later.Good luck! I’m interested in seeing how JS to WASM compilers can speed up edge rendering use cases. WASM opens the possibility of really cheap request isolation, far faster than process forking. But JS interpreters in WASM are currently so much slower that they still lose out performance wise overall.
https://www.microsoft.com/en-us/research/uploads/prod/2019/0...
Is this true? Rust is hyped like crazy and seems to be used everywhere these days.
We were actually hiring for a couple of roles, although we just sent out two offers, so we won't be if they get accepted.
There aren't that may new projects where rust would be a good fit. And projects in C++ won't be rewritten in rust.
Google (collectively) have written quite a bit about Rust adoption going back at least a couple of years. It'd kinda surprise me if there weren't some drive to write gmail/googledocs in Rust and deliver them as WASM. Meta/Facebook have some strong internal Rust evangelism going on.
I doubt it's a good idea, but it's likely my first trial "lets write a Rust project" will be an in-browser Rust/WASM thing.
What kind of apps?
On the backend there are plenty of mature ecosystems already that have been around for decades. Even focusing only on performance there's not a huge difference with say .NET or Java when looking at web benchmarks like TechEmpower[1].
On the frontend nothing can really beat the DX of using Vite with JS (hot reload of JS components, styles, etc). I don't know if it's even possible to get hot reload with WASM.
I could be wrong but it sounds like doing a complex web project in Rust would be a pain with not a lot of benefits over more popular and mature solutions.
[1] https://www.techempower.com/benchmarks/#hw=ph&test=fortune&s...
Heh? I really like Rust, but it has absolutely zero advantage for this domain compared to the existing million choices. Unless you are doing some low-end web stuff with packets, any managed language will have a much better developer experience. Async rust is not particularly easy, and something like Java's virtual threads will give you both the ergonomics and the throughput, and then we haven't even talked about how much bigger the relevant ecosystem is (remember that the only order of magnitude improvement in dev productivity is from code you don't have to write)
For example, I wrote an ssg in rust but I was able to fully compile it to wasm and it works in the browser.
C++, Java, Go, Erlang, Rust, PHP, JavaScript, C#, whatever
Aren't almost all new projects that otherwise would have been written in C or C++ good fits for Rust?
The C++ ecosystem is too strong.
There are many industries like game dev and audio dev where C++ is not going to be replaced any time soon, even for new projects.
Also plenty of apps that need high performance crossplatform GUI will probably keep relying on QT. Apps like Da Vinci Resolve or Autodesk Maya.
Certainly a lot, and most new C/C++ (and even Go) projects will mention that they considered Rust before choosing a different language.
Second, it's obviously much easier to double your user base from 2 to 4, than from 10 million to 20. New languages tend to have a fast initial growth, but then the curve flattens and no significant change comes after. Java hasn't been on a decline in the absolute sense, the whole market has just grown and has more players now, so the same mindshare gives less of a percentage now. Nonetheless, no language has come even close to the top 3 languages (js, python, java) in popularity that were released in the last 20 years, so what makes you think that Rust will be the one that avoids the flattening of its growth?
Sure, lots of new project/code uses languages like Go these days. But Java is still very dominant, especially at companies like Amazon. It currently sits ar #3 on TIOBE.
Do you have the results of test262_runner.rb? I came to know about test262 at a talk by the porffor's author and something like https://github.com/CanadaHonk/porffor?tab=readme-ov-file#tes... in README would be great to show this progress. Great project by the way!
Once I finish implementing `await` and generators, which are the last hard to implement semantic concepts, I will be implementing those low hanging fruits. It's hard to say how much coverage that will give me, but just to give an example: currently 1200 tests fails, cause `object["foo"]` syntax is not implemented. Ie. `object.foo` works, but `object["foo"]` does not. It doesn't mean that those 1200 tests automatically will pass, cause they might be testing other stuff, but there is a lot of such relatively simple syntax ommissions that make hundreds of tests fail.
And yes, I would love to have a nice graph like porffor has! :D
Somewhat linked questions: How does it react if it encounters e.g. web APIs inside the JavaScript code or other global identifiers only defined in some environment (e.g. a recent browser, Node.js etc.)? Or if it's not intended for those environments, how are you supposed to do I/O when using this?
This is all due to a fact that historically WASM was a very simple runtime. It was relatively easy to compile C code to WASM, just like you compile C code to machine code, but even though a WebAssembly is a kind of interpreter by itself, it wasn't easy to interpret higher level languages on top of it.
With new proposals being standardized, like garbage collection support or exception handling support, WebAssembly becomes much more powerful interpreter, with stuff like structs, arrays, function references etc.
Jaws leverages that fact translating JS code to WASM code in a way that WASM interprets the resulting code, without the need of a JS engine like SpiderMonkey. In practice it mainly means that a binary generated by Jaws will be probably under 50KBs vs 10MBs when you compile SpiderMonkey to WASM and run your script on top of that. Memory usage will be also significantly lower. For companies like Fastly this would mean orders of magnitude lower memory usage and thus server costs. For companies like Shopify it would mean they could leverage JavaScript code already available (think NPM packkages) and JavaScript ecosystem for people writing plugins for Shopify's backend.
> is it intended to be a tool compatible with browsers and other WASM runtimes or is it only compatible with a runtime linked to the project
The only runtime the project uses is WebAssembly. The generated code is mostly 3k lines of WAT code form this file: https://github.com/drogus/jaws/blob/main/src/wat/template.wa... and whatever your JS code is translated to. For example for a very simple program like "console.log('foo')" the entire "generated" part is this: https://gist.github.com/drogus/1c49c25ed0b14804b2f27e10d2a79..., which more or less prepares an argument (with new_static_string) and then calls console.log. Right now I need a bit of glue code on the host, but eventually it will be possible to execute such a binary with any runtime that supports WASIp2, WASM GC and exception handling proposals.
> Somewhat linked questions: How does it react if it encounters e.g. web APIs inside the JavaScript code or other global identifiers only defined in some environment (e.g. a recent browser, Node.js etc.)? Or if it's not intended for those environments, how are you supposed to do I/O when using this?
None of this is implemented yet, but I can tell you how it will work. I plan to support Node.js APIs through WASI. WASI is a standard for communicating between WASM programs and the outside world. For example WASI defines a standard set of functions you can use to send an HTTP request, or write to STDOUT, or read/write to a file. So when I get to APIs like `fetch` or `fs`, it should work with any runtime that supports WASI preview2. Browsers could also be supported with polyfills, but in this case I/O support is more custom. Like, if you decide you allow WASM programs to write or read files, you would have to provide a mechanism to do that, for example save files to localStorage or an SQLite database compiled to WASM (or I guess even send them to S3 or something along the lines).
A wasm runtime can be far more lightweight than node, not only because node itself is a wasm runtime, plus a lot of other things. Wasm could (or does, already?) occupy a sweet spot where platform independent extensibility is desired, but where that is not enough of a core feature to make inclusion of a heavier runtime advisable. Kind of like how Lua has its place, but with more focus on near-native speed and less focus on ad-hoc programming (aka scripting).
WASM specifies UTF-8 for the encoding of names in its file formats, but that doesn't involve the runtime VM.
Does it support ArrayBuffers?
Btw, I am very bad at naming, I chose the name cause it has most of the letters that "JS-WASM" has (or all of them if you consider W is just inverted M)
Anyway, it's a cool project. Thanks for sharing!
FWIW, for the audience, both you and I know the game here is "can we define a broad enough, yet narrow enough, category that someone could confuse the screenreader with the WASM compiler, such that it can be claimed to be 'emotionless' to say there's a significant collision and the WASM compiler needs a rename."
First, there's certainly room for conversation, emotionless doesn't mean provably unambiguously correct and everyone else needs to agree and not reply. :)
Second, it's clear you do have emotions, ex. see how you're policing whether its okay to "joke", where "joke" is me going to great lengths to indirectly indicate the possibility this is less than 100% unambiguously correct in as non-personal a way as possible. I did that because the initial curt, policing, tone indicated strongly that you would react poorly to any indication this was anything other than unambiguous. And here we are.
Very cool and interesting project! How are build times? And how big are the artifacts?
I'll for sure keep an eye on this, and add it to my ever expanding list of tech to explore.
Thank you for sharing!
One interesting thing is that `eval()` support will require custom WebAssembly host functions, cause you can't do custom code generation in WASM. Thus by default the project will assume "no eval" compilation. In this mode it will be possible to do a lot of optimizations, like for example remove unused parts of the language/types, do certain optimiztions knowing exactly what types the script is dealing with etc. So a simple script that doesn't use a lot of the builtins should eventually result in a fairly small binary.