The C ABI approach works fine but becomes complicated when you want to pass things that aren't fixed-length, because unlike the C ABI usage when linking different libraries into the same address space, the host and the module run in different address spaces. Eg if the host wants to pass a string to a module fn, it first needs to call a different "malloc" module fn to allocate some space in the module address space and return that address, then the host writes the string to that address, then calls the original fn it wanted to call with that address, then calls a third "free" function at the end to release that allocation. Does that work? Of course it does. But the component ABI abstracts over all that for you and lets you call the function with the host's string type, and the runtime on the host side and bindings on the module side handle all the thunking so that it appears on the module side as the module's string type.
TFA doesn't seem to have any arguments other than "It's too many new words for me to learn so it's unnecessary I decided." Eg:
>And don't get me started on WIT's kebab-case identifiers (function names, interface names...). Why??? How can a specification about cross-language interoperability can come with a convention that basically no programming language use?
The point of the kebab case is that it does *not* show up in the generated bindings. It's processed by the bindings generator into the appropriate casing for the language. Eg a function name `foo-bar` becomes `foo_bar` in Rust, and a type named `foo-bar` becomes `FooBar`.
Since the point is to enable component-level interop, not fine-grained function interop, you can instead define a simple interchange format (more JSONish than IDLish) and write the library interfaces accordingly. More of a microservice approach than a linker approach.
> I strongly believe that async is the new billion dollar mistake of the 2020's: a design aberration that wasted so much developers time that it had cost billions of dollars to companies.
Yes. Nicely put
Async as a paradigm has probably created billions of dollars in that it's allowed many many many developers to reasonably scale beyond what they could've otherwise.
Just some background first: one of the billion dollar mistakes is the null pointer which is a special value to be assigned to any type. It was inherent in the first high (today considered low) level languages. Those languages (C most importantly, then Java and nowadays even Go) enabled many more programmers to create programs and they likely would not have been able to, had they been forced to write assembly. So, it's a billion dollar mistake within a trillion dollar revenue.
The async now solves a similar practical problem but in the space of prallelism (or concurrency, in some cases). A different approach might have given us the same result, but a different implementation that might be just as approachable.
Optionals and Results have given us a better way than to have nulls, and maybe golang style channels could have given us a better way to handle async?
I recommend this talk by Luke Wagner on async plans in WASI 0.3 (https://youtu.be/y3x4-nQeXxc) for background on how it will work.
To summarise, from an API perspective, the caller and callee won't know if the other is async or not. When calling async from non-async, an event loop is inserted at link-time and it blocks.* When calling non-async from async, the callee will get suspended if it tries to do blocking IO. That still leaves the problem of long-running compute without IO in a non-async context, but at least you're not wasting CPU time in that scenario.
* If the host runtime already has an event loop, I assume the callee will get added to that.
Unfortunate.
I think that these days the scammers have won. They can do a better job than I can at being authentic.
FWIW based on the comments I actually prefer a richer runtime that allows some of the language level features that have been hard to get support for. I think having mainstream support for effects would be sort of magical.
Actual isolated modules? Talk about living in the future.
Wasm is a lot like the jvm and flash, which makes some people hate it. But for me the problem with those platforms was the execution, not the idea.
I'm cautiously optimistic that wasm will finally give us a good high performance cross platform secure execution target for the web.
I have a pretty trivial webapp written in Yew and I stopped working on it once I saw that the wasm artifacts were weighing at 4MB (uncompressed) for relatively little functionality. THIS is what is driving the next round of "work" on WASM: to wring more functionality out of a system (WASI 0.1) designed as a drop-in replacement for emscripten output. As an aside on this point, the author is waaaay in front of their skies with basically all of their critiques around ByteCode Alliance; A lot of innuendo to basically serve a rhetorical point that isn't really true (WASI 0.1 is "good enough"). It has drawbacks! That's what the iterations on the protocol are exploring!
And this tech is cool and all, but right now a reasonably-vanilla typescript react app w/ a modern bundler (ie including stuff like router, redux, oidc, etc) is beating the breaks off of a similar app in Rust or C#/Blazor in terms of bin size. And there's no perf or API-surface argument that overcomes this. And it has chilling effect on developers when they reach for this tech.
Promise you won't tell the GC'd language enthusiasts this, but wasm engines supporting the wasm-gc proposal don't need to ever run a garbage collector. A simple bump allocator is 100% compliant, as long as the module's memory gets cleaned up once it terminates. Wasm engines for embedded systems will probably do exactly that, and leak memory rather than collect garbage. The web already has a garbage collector for JS, so not a big deal there either. Bloat has its cost, but at least it's only paid by cloud/edge/desktop and other use-cases that can afford to put it in their engine.
I think wasm-gc is worth it for WebAssembly. The dream is "run any language, anywhere" but it's always been easier for low level languages like C, C++ and Rust, because their binaries are smaller. Maybe with things like wasm-gc, WebAssembly can be great for C, C++, Rust, but also JavaScript and Python, Java and Go, OCaml, Perl, and whatever language gets sprung on us next.
For those that aim to continue working on top of WASIp1, WASIX (https://wasix.org) might be a great way to get your programs with sockets and threads fully running on Wasm.
Note: I work at Wasmer (https://wasmer.io), a WebAssembly runtime.
This whole component model mess on the other hand though: Don't get me started with all these kebab case worlds
I see the article says "sabotaged", so perhaps that was fixed? Or the titles never matched?
Many of us (haters), are old timers seating on the saloon bench seeing yet another slew of gold diggers arrive full of enthusiasm into town.
This time is going to be different, and it will take over the world (TM).
I'm excited for having extremely lightweight sandboxed. WASI enables having a runtime with a bunch of loaded libraries. You can start a very small script & link in the already loaded modules on the fly, in a very secure fashion.
It's be like having an isolate-oer-requesf model. Super secure, but with fantastically low overhead. Ideally instead of having a huge app server, a front end router would be picking which specific actions to run.
The ability to spin up a cast number of very lightweight secure processes and have them communicating with each other is fascinating. App servers as we build them are ghastly complicated swiss army knives, and being able to have something like a "serverless"/lambda architecture where we can narrow the scope down & really think about what has to be in a given request handling's process could be a big operational boon, if we're willing to once more venture away from the comforting warmth of the monolith that folks love huddling up next to.
As usual though hope & possibility is speculative & nuanced & diverse, and disbelief & disgust is blanket & unifying. I have no clue how I'm still so shocked to see negativity upvoted, positivity out down upon, after it happening so many times but I keep being surprised how strongly negativity reigns. And how fiercely & widely it downvotes! There's just something about the disbelievers & skeptics that they have to smash the downvote, can't abide possibility or excitement; there's never any wait and see, never any maybe about it. Just doom & gloom on and on.
The part that actually pertains to WASM - async/await - exists because everything in a browser lives in Someone Else's Single Threaded Event Loop. Writing code that lives in an event loop is pure pain, and async/await exists solely to fix this problem. The billion dollar mistake is not adding async/await to programming languages, it's single-threaded event loops. Anyone talking about C10K or non-blocking I/O in regards to async/await is probably missing the point, because aside from one stubbornly single-threaded programming language[0] you can launch threads to handle reading or writing data and sockets.
[0] JavaScript. It's always JavaScript.
If you were thinking Python, you're wrong. Even with the GIL, Python supports threads, and concurrent I/O is one of the few reasons why they're useful.
In case you absolutely do not care for WASI but love WebAssembly for the web.
And keep in mind that the perspective of the author is that things will only get worse from hereon, with regard to WASM.
We have the basic primitives like signed and unsigned integers of various sizes, floating point numbers, bools and chars.
Remember that wasm components are like shared libraries (dll/so objects). Shared libraries themselves have dependencies (eg: vlc needs qt, which needs mesa, which needs x11/wayland etc..). Each component/shared library has a set of imports from other shared libraries and exports items to other shared libraries or apps.
For example, lets say that I want give a vector/array as an argument or receive it as the return type. On native libs, we just give a pointer + len as arguments, and the function can simply read/write using that pointer.
Except, wasm components are isolated (shared-nothing model). So, I can't just allocate the bytes and give a "pointer" to the jpeg decoder. Because both of us don't share the memory. This has a few reasons:
1. security: separate memories make sure that a component can't read/write another component's memory. 2. safety: If we don't have higher level types, then people will just pass around blobs and cast those bytes into types. Imagine one component thinks of rect as `Rect { x, y, w, h: f32 }` and another component thinks `Rect { x1, y1, x2, y2: f32}`. Without "record" types, we can't find that error. 3. flexibility: Lets say we want to pass around a list of strings between components. how would you do it between rust and js? To let each language feel natural, we need to "copy" these higher level types across the boundary (and wasm needs to understand these higher level types) into the respective suitable types.
This is why we have records (structs), strings, list<T>, variants (tagged unions), Option<T> and such types to allow for a feature-rich API. These are all passed by copy at the boundary with proper validation by the runtime in advance, so you get both performance, safety and ergonomics.
Finally, we also need to talk about "ownership", because some objects (like files via file descriptors) need to be passed across component boundary and we need to wasm let somehow know that we are passing on ownership of the file. We do this with "resource" (object with an ownership like a file descriptor or host native object or socket etc..). And wasm must also ensure that the object will be alive for the duration of the borrow.
The rest of the WIT is simple.
Interface is literally just a group of type signatures or objects. just like a module in python, rust. In C world, we usually just prefix the library/type name for all the function that belong to a certain library/type. In WASI, we just place the related fns inside an interface.
Similarly, a world is just a group of imports and exports that represent a component. world = component. world can import/export types/interfaces/fns/data. You can have multiple 'worlds' and interfaces within a wit file.
And a package is a group of wit files. similar to a java or go package that a file belongs to.
Its not really hard to understand. Most of the terminology directly translates to what we all see in any modern language like js, py, java, rust, go etc..
And the docs are not accessible at the moment, because its still a WIP and unstable. They are experimenting with rust and js to see how well this model works in practice.
Uhh really? You just got done pointing out
> But, WASI 0.1 was severely limited about the type of data that it could exchange: basically integers and pointers to buffers.
We obviously couldn't stop there.
The author has all sorts of shit to throw about the interface definitions being way more complex than they want.
It turns out calling other languages isn't just about calling their stuff. You also need to be able to import and then latter link the things you want to use. Being able to say what it is you want brought in, what you want to link to, that's stuff the runtime needs to be able to do.
Look at c and c++. They've been around for decades and there's still nearly no mainstream package/library management. Because it looks like what Kerkour asked for, because everything is too simple in that world.
You need this stuff. You need to be able to create high level semantics to interoperate across. You need a rich enough ABI to let languages negotiate for & get the things they're going to call.
The qualms against async are even less well defined & even more unsupported, which is compensated for being ever more foaming at the mouth & wild gesticulating. Rather than acknowledge that yeah, some people like & use async in languages, there's utterly untargeted shade of the broadest degree:
> Most importantly, after all these years, nobody knows when to use [rust's async] or not! Should this library be async or not?
Io-less libraries that can put off being async are in fact excellent. But there still, in most systems, are things happening over time, and async happening in Python and Node and others radically upped the game of what was possible. And in the past decade have even evolved into something pretty nice & great & usable.
But Rust having some difficulty figuring out how to manage their ecosystem is, to Kerkour, apparently enough to damn the whole enterprise, "The new billion dollar mistake." Having been around for cgi-bin and mod-perl, I don't think I'm so massively massively confidently assured.
Things aren't always exactly as perfect as we might want. And that just really drives some people wildly mad, is inexcusable. 'We should never have tried, ruin to those trying to improve things, & drop it all & go back!,' seems to be the message. Actually the message here is even worse, more, 'these people are vultures trying to syphon money with the express intent to create waste & milk the anarchy,' which is some contagious shit to be spewing.
This seems so overblown. WIT's are not that complex. Theres reasons stuff is like this (permitting wasm engines form a registry to give people what they're asking to use, without needing internals that would have to DIY this all themselves). And maybe such a broad objective as a universal computing runtime might be possible with less. But honestly the risk of underbidding & failing to connect different systems well seems far worse than the risk of, I dunno, what the author seems to be apoplectic about, perhaps maybe enjoying using a package manager to help satisfy dependencies.
One thing the author is right about, that makes me extremely sad:
> I hardly see browser vendors implementing this
I can excuse this today, because it is unknown. But wow it's scary as hell seeing how uninvolved & interest the browsers look. The browsers seem full speed ahead building their own take on platform, doing their own file system APIs and what not. There's great efforts by many to bridge the two worlds, to create WASI runtimes for the browser, but some day I really hope the promised universal machine of WASI is something the web can enjoy and use. But I'm also not in a hurry; I think there's a lot of figuring how best to make this wasi 0.2 world nice & letting languages figure out their own tooling to come play. Patience & improving & iterating is good; trying is good. We improve & progress through time and effort.