aboutsummaryrefslogblamecommitdiff
path: root/_posts/2020-02-11-on-webassembly-killing-javascript.md
blob: bab3b6e2fc727377c53363f692d9b46e98e0c71e (plain) (tree)













































































































































































































                                                                                   
---
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 multiplatformr 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 everywhere[^1]. This is due to
it having very few dependencies and

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 <stdio.h>

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 <stdio.h>
#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

<script type="module">
 import * as api from "./api-wasm.js";

 WebAssembly
   .instantiateStreaming(fetch("add.wasm"), { env: api })
   .then(({instance: {exports}}) => {
     const added = exports.add(4, 5);
     console.log("Adding 4 and 5:", added);

     exports.persistInt(6);
     const persisted = exports.retrieveInt();
     console.log("Persisted number:", persisted);
   });
</script>
```

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:
FIXME
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