Skip to content

Commit 93c9e32

Browse files
committed
Answer "why not Rust, Go, or C" with the measured numbers
The old answer conceded the ground ("excellent when a rewrite makes sense"), argued from preference ("the hot path you want to keep"), and undersold the result as "comparable". The bench corpus says otherwise: wasm from rustc, clang and zig runs about 2× behind JZ by geomean and Go's over 4×, and their native binaries still trail, with native C level. Say that, on the site and in the README's comparison bullet.
1 parent 1ca26e8 commit 93c9e32

2 files changed

Lines changed: 17 additions & 14 deletions

File tree

‎README.md‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,10 @@ JavaScript's bounds checks.
253253
to Porffor's native artifact on speed or size per case or by geomean.
254254
- **[scriptc](https://github.com/vercel-labs/scriptc)** also AOT-compiles typed JS/TS without an engine (TS annotations → LLVM), embedding QuickJS only as an opt-in fallback for dynamic code. It is native-first with WASI as a target; JZ is WASM-first, infers types from idiomatic untyped JS, and keeps dynamic fallbacks inside the WASM module.
255255
- **[AssemblyScript](https://github.com/AssemblyScript/assemblyscript)** produces lean WASM, but is not directly executable JavaScript.
256-
- **Rust, C, Zig, Go, and MoonBit** offer explicit static types and mature native
257-
toolchains, but require a second implementation when the source of truth is JS.
256+
- **Rust, C, Zig, Go, and MoonBit** compiled to wasm run behind JZ by geomean on
257+
the corpus: rustc, clang and zig about 2×, Go and MoonBit over 4×. As native
258+
binaries Rust, Zig and Go still trail and C is level, so a rewrite buys a
259+
second toolchain and test suite for slower wasm.
258260
- **[Javy](https://github.com/bytecodealliance/javy)** and
259261
**[ComponentizeJS](https://github.com/bytecodealliance/ComponentizeJS)** accept
260262
broader JavaScript by shipping an interpreter or engine inside WASM.

‎index.html‎

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,8 +1349,8 @@ <h1>JS as it is<br class="hb">to native speed</h1>
13491349
<path d="M6 9l6 6 6-6" />
13501350
</svg></summary>
13511351
<div class="ans prose">
1352-
<p>JZ compiles a distilled JavaScript subset, Crockford’s “good parts” – into native-grade WASM.</p>
1353-
<p><b>Valid JZ is valid JS</b>. Same source runs as plain JS or compiles without rewrite to <code>.wasm</code> – sandboxed, portable, memory-safe. No runtime, no GC, no type annotations, auto-SIMD, deterministic output.</p>
1352+
<p>JZ compiles a JavaScript subset into native-grade WASM.</p>
1353+
<p><em>Valid JZ is valid JS</em>: same source runs as plain JS or compiles to <code>.wasm</code> – sandboxed, portable, memory-safe. No runtime, no GC, no type annotations, auto-SIMD, deterministic output.</p>
13541354
<table>
13551355
<thead>
13561356
<tr>
@@ -1361,23 +1361,23 @@ <h1>JS as it is<br class="hb">to native speed</h1>
13611361
<tbody>
13621362
<tr>
13631363
<td>DSP, audio, synthesis</td>
1364-
<td>UI, DOM, frontend state</td>
1364+
<td>UI, DOM, frontend</td>
13651365
</tr>
13661366
<tr>
13671367
<td>Images, video, pixels</td>
1368-
<td>Network, hot I/O, serving HTTP</td>
1368+
<td>Network, hot I/O, serving</td>
13691369
</tr>
13701370
<tr>
13711371
<td>Simulation, physics, games</td>
1372-
<td>Dynamic object models and monkey-patching</td>
1372+
<td>Dynamic objects, monkey-patching</td>
13731373
</tr>
13741374
<tr>
13751375
<td>Parsers, codecs, compression</td>
1376-
<td>Allocation-heavy, long-lived object graphs</td>
1376+
<td>Allocation-heavy, long-lived states</td>
13771377
</tr>
13781378
<tr>
13791379
<td>Scientific, numeric, edge ML</td>
1380-
<td>Security-sensitive cryptography and arbitrary-precision integers</td>
1380+
<td>Security, cryptography, arbitrary-precision integers</td>
13811381
</tr>
13821382
<tr>
13831383
<td>Hashing, checksums, RNG</td>
@@ -1393,22 +1393,22 @@ <h1>JS as it is<br class="hb">to native speed</h1>
13931393
<path d="M6 9l6 6 6-6" />
13941394
</svg></summary>
13951395
<div class="ans prose">
1396-
<p>Modern JavaScript compiles: classes, generators, async/await, destructuring, BigInt, typed arrays, Map/Set, RegExp, Date, JSON, timers. What JZ refuses, at compile time:</p>
13971396
<div class="subset">
13981397
<div class="ring out">
13991398
<span class="rl">Not supported</span>
14001399
<span class="t">eval Function with</span><span class="t">Proxy Reflect</span><span class="t">descriptors</span><span class="t">prototype chains</span><span class="t">top-level await</span><span class="t">import()</span><span class="t">DOM</span><span class="t">Node Intl Temporal</span>
14011400
</div>
14021401
</div>
1403-
<p>And what differs: no GC (call <code>memory.reset()</code>), 64-bit BigInt, compile-time regexes, ASCII case and UTC dates. <a href="https://github.com/dy/jz#faq" target="_blank" rel="noopener">Details →</a></p>
1402+
<p>What's supported: classes, generators, async/await, destructuring, BigInt, typed arrays, Map/Set, RegExp, Date, JSON, timers.</p>
1403+
<p>What differs: no GC (call <code>memory.reset()</code>), 64-bit BigInt, compile-time regexes, ASCII case and UTC dates. <a href="https://github.com/dy/jz#faq" target="_blank" rel="noopener">Details →</a></p>
14041404
</div>
14051405
</details>
14061406

14071407
<details name="faq">
14081408
<summary><h2 class="fq">Why no types?</h2><svg class="chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
14091409
<path d="M6 9l6 6 6-6" />
14101410
</svg></summary>
1411-
<div class="ans prose">Ordinary code already carries useful type evidence: <code>let x = 0.5</code>, <code>Float32Array</code>, an array index, a loop counter. JZ infers it instead of turning the file into another language. Ambiguous values take a slower, always-correct dynamic path.</div>
1411+
<div class="ans prose">JS code already carries useful type evidence: <code>let x = 0.5</code>, <code>Float32Array</code>, an array index, a loop counter. JZ infers it instead of turning the file into another language. Ambiguous values take a slower, always-correct dynamic path.</div>
14121412
</details>
14131413

14141414

@@ -1417,7 +1417,7 @@ <h1>JS as it is<br class="hb">to native speed</h1>
14171417
<path d="M6 9l6 6 6-6" />
14181418
</svg></summary>
14191419
<div class="ans prose">
1420-
<p>Porffor aims to cover the full JS spec but emits no WASM (its 2026 rewrite compiles through C to native) and runs slower than V8 on the <a href="bench/">cases</a> it completes; scriptc makes native CLI binaries from TypeScript, no WASM target; AssemblyScript compiles a typed TypeScript dialect to WASM.</p>
1420+
<p>Porffor aims to cover the full JS spec but emits no WASM and runs slower than V8 on the <a href="bench/">cases</a> it completes; scriptc makes native CLI binaries from TypeScript, no WASM target; AssemblyScript compiles a typed TypeScript dialect to WASM.</p>
14211421
<p>JZ compiles plain JS that still runs and tests as JS, and the release gate keeps its WASM fastest per case; the price is the overdynamic constructs it refuses.</p>
14221422
</div>
14231423
</details>
@@ -1427,7 +1427,8 @@ <h1>JS as it is<br class="hb">to native speed</h1>
14271427
<path d="M6 9l6 6 6-6" />
14281428
</svg></summary>
14291429
<div class="ans prose">
1430-
<p>Rust, Go, and C are excellent when a rewrite and second toolchain make sense. JZ is for the hot path you want to keep in JavaScript: one source, one test suite, a JS fallback, and comparable WASM or <a href="#native">native</a> performance.</p>
1430+
<p>If it is already Rust, keep it in Rust. If it is JavaScript, a rewrite buys a second language, toolchain and test suite, a marshalling boundary on every call, and slower wasm: on the <a href="bench/">corpus</a>, rustc, clang and zig output runs about 2× behind JZ by geomean, and Go's over 4×.</p>
1431+
<p>Their native binaries do not change the picture: Rust, Zig and Go still trail JZ's wasm by geomean, and C is level.</p>
14311432
</div>
14321433
</details>
14331434

0 commit comments

Comments
 (0)