--- title: On WebAssembly killing JavaScript date: 2020-02-11 layout: post lang: en ref: on-webassembly-killing-javascript --- When discussing WebAssembly (WASM), I often see people portraiting it too much as a JavaScript replacement, but I think this framing misses the point of some of the aspects on how WASM can be a great tool: being a portability oportunity, which means increasing the reach to code. If you think of WASM strictly as a optimization of JavaScript, that's where you'll end up: WASM is the same as JavaScript, but faster. But there's a more interesting aspect (to me) of it: portability. That means you can now write multiplatforme code that runs everywhere. I mean, everywhere, even in the browser. Let's imagine how you could write SQLite and mke it run on the Web. # SQLite If I were to create, say, SQLite today, I would consider adding web support for it. SQLite already is available almost everywhere[^1]. This is due to it having very so few dependencies, Imagine having writing SQLite today There are also other legimate uses of WASM, such as WASI and etc. Here's how I would start writing an application that could run on any POSIX system and, on top of that, could run on the browser: ``` // api.h extern void platformDependentPersistInt(int); extern int platformDependentRetrieveInt(); // api-posix.c /* POSIX implementation of "api.h" interface to be used in non-web contexts */ #include void platformDependentPersistInt(int n) { FILE* fp = fopen("/tmp/persisted.txt", "w+"); fprintf(fp, "%d", n); fclose(fp); } int platformDependentRetrieveInt() { FILE* fp = fopen("/tmp/persisted.txt", "r"); int persisted = fgetc(fp); return persisted; } // api-wasm.js /* WASM implementation of "api.h" interface to be used in web contexts */ export const platformDependentPersistInt = (n) => localStorage.setItem("persisted", n.toString()); export const platformDependentRetrieveInt = () => parseInt(localStorage.getItem("persisted")); // add.h int add(int a, int b); void persistInt(int n); int retrieveInt(); // add.c #include "api.h" int add(int a, int b) { return a * a + b; } void persistInt(int n) { platformDependentPersistInt(n); } int retrieveInt() { return platformDependentRetrieveInt(); } ``` ``` // main.c #include #include "add.h" int main() { int added = add(4, 5); printf("Adding 4 and 5: %d\n", added); persistInt(6); int persisted = retrieveInt(); printf("Persisted number: %c\n", persisted); return 0; } // index.html ``` In order to ``` // server.py #!/usr/bin/env python import SimpleHTTPServer import SocketServer PORT = 8001 class Handler(SimpleHTTPServer.SimpleHTTPRequestHandler): pass Handler.extensions_map['.wasm'] = 'application/wasm' httpd = SocketServer.TCPServer(("", PORT), Handler) print "serving at port", PORT httpd.serve_forever() ``` Dependency graph: api-posix.c api-wasm.js api.h add.h add.c main.c index.html Compiling and running the POSIX code: ```shell $ clang -o add main.c add.c api-posix.c $ ./add Adding 4 and 5: 21 Persisted number: 6 ``` Compiling and running the WASM ```shell $ clang \ --target=wasm32 \ -nostdlib \ -Wl,--no-entry \ -Wl,--export-all \ -Wl,--allow-undefined \ -o add.wasm \ add.c $ ./server.py ``` After opening the browser, the console shows: ``` Adding 4 and 5: 21 Persisted number: 6 ``` Rust, C, Zig No Emscripten, no GC, no runtime Emscripten 11KB # Limitations "System call" cost in WebAssembly. WASM is very new, no flush guarantees. Confusing dependency tree AFAICT you can't package WASM with JavaScript. [^1]: [Platforms supported by SQLite are](https://sqlite.org/features.html): "Android, *BSD, iOS, Linux, Mac, Solaris, VxWorks, and Windows (Win32, WinCE, WinRT) are supported out of the box. Easy to port to other systems". https://sqlite.org/selfcontained.html