HNHacker News
TopNewBestAskShowJobs

pdubroy

1,074 karma · joined March 31, 2008

http://dubroy.com/blog - on programming, usability, and design
submissionscomments
pdubroy··on Ohm's Peg-to-WASM Compiler
From https://ohmjs.org —

Here are some awesome things people have built using Ohm:

- Shopify's theme-tools (https://github.com/Shopify/theme-tools/), used in their online code editor and the official VS code extension.

- Seymour (https://github.com/harc/seymour), a live programming environment for the classroom.

- Shadama (https://tinlizzie.org/~ohshima/shadama2/live2017/), a particle simulation language designed for high-school science.

- Slang (http://slang.kylestetz.com/), a browser-based audio programming language, and turtle.audio, a music sequencer inspired by turtle graphics programming.

- Simpletalk (https://github.com/dkrasner/Simpletalk) is an expressive, programmable authoring system inspired by Hypercard and Smalltalk. (See also the StrangeLoop talk).

- Wildcard (https://www.geoffreylitt.com/wildcard/), a browser extension that empowers anyone to modify websites to meet their own specific needs, uses Ohm for its spreadsheet formulas.

- JAMScript (https://citelab.github.io/JAMScript/) is a programming language for edge-based IoT applications.

- Bruno (https://github.com/usebruno/bruno) is an open source IDE for exploring and testing APIs.

It has also been used in a number of projects by Ink & Switch (https://inkandswitch.com), including Potluck (Dynamic documents as personal software: https://www.inkandswitch.com/potluck/), the Deja Vu project at MIT (https://sdg.csail.mit.edu/project/deja-vu/), ...

pdubroy··on What happened to WebAssembly
Shameless plug: if you're interested in learning WebAssembly — like really learning the bytecode format and how it works — you might like our book, WebAssembly from the Ground Up: https://wasmgroundup.com.

It starts with handcrafted bytecode for a minimal Wasm module in JavaScript, and then guides you through the creation of a simple compiler for a toy language.

pdubroy··on Golang's big miss on memory arenas
I know there have been solutions in the Java world for >20 years, though I can't comment on well they work in practice.

From a quick search, _An Implementation of Scoped Memory for Real-Time Java_ (https://people.csail.mit.edu/rinard/paper/emsoft01.pdf) provides a decent overview:

> Real-Time Java extends this memory model to support two new kinds of memory: immortal memory and scoped memory. Objects allocated in immortal memory live for the entire execution of the program. The garbage collector scans objects allocated in immortal memory to find (and potentially change) references into the garbage collected heap but does not otherwise manipulate these objects.

> Each scoped memory conceptually contains a preallocated region of memory that threads can enter and exit. Once a thread enters a scoped memory, it can allocate objects out of that memory, with each allocation taking a predictable amount of time. When the thread exits the scoped memory, the implementation deallocates all objects allocated in the scoped memory without garbage collection. The specification supports nested entry and exit of scoped memories, which threads can use to obtain a stack of active scoped memories. The lifetimes of the objects stored in the inner scoped memories are contained in the lifetimes of the objects stored in the outer scoped memories. As for objects allocated in immortal memory, the garbage collector scans objects allocated in scoped memory to find (and potentially change) references into the garbage collected heap but does not otherwise manipulate these objects.

> The Real-Time Java specification uses dynamic access checks to prevent dangling references and ensure the safety of using scoped memories. If the program attempts to create either 1) a reference from an object allocated in the heap to an object allocated in a scoped memory or 2) a reference from an object allocated in an outer scoped memory to an object allocated in an inner scoped memory, the specification requires the implementation to throw an exception.

pdubroy··on WebAssembly from the Ground Up
Awesome! You're exactly the kind of person we were thinking of when we wrote the book…experienced programmers who are interested in understanding things at a lower level.

Let us know how it goes! You can find us in the book Discord, or email us at hello@wasmgroundup.com.

pdubroy··on WebAssembly from the Ground Up
Edit: changed slightly to provide a more useful answer.

No, it doesn't — not this version of the book at least. We only cover WebAssembly 1.0.

That said, as my co-author says below, there's really not much to tail calls. Once you've worked through the book, you'd be able to grok tail calls pretty quickly.

As an aside — 2.0 was announced just a few weeks after we launched the book, and 3.0 a few months ago. And with 3.0 (which added tail calls), the spec has more than doubled in size vs 1.0, so it would be hard to cover everything.

We've talked about doing a new chapter to cover some of the interesting parts of 2.0 (e.g. SIMD), but covering everything in 3.0 (garbage collection, typed reference, exception handling, tail calls…) feels almost like an entire 2nd book!

pdubroy··on WebAssembly from the Ground Up
I agree, it really is quite approachable.
pdubroy··on WebAssembly from the Ground Up
Ah, good catch! I see them in one of the screenshots. Those are just inlay hints, they're not in the source code. (The editor is https://zed.dev)
pdubroy··on WebAssembly from the Ground Up
Thank you!

I would 100% agree that the spec is quite readable. At the top of our Minimum Viable Compiler chapter, we say:

> The binary module format is defined in the WebAssembly Core Specification. You’ll notice that we back up many of our explanations with reference to the relevant part of the spec. One of our goals with this book is to convince you that the spec is a valuable resource that’s worth getting familiar with.

I think the spec is great as reference material, but we wrote the book to be more of a tutorial. We've talked to many people who say they've looked at the spec, but find it too overwhelming. For those people, we hope the book provides a good structure that ultimately helps them become comfortable with the spec!

pdubroy··on WebAssembly from the Ground Up
Yes, it can all be found here: https://github.com/wasmgroundup/code

Over the course of the book, we also build up a small library for creating Wasm modules and emitting bytecode; that's available as an NPM package (https://www.npmjs.com/package/@wasmgroundup/emit) and the code is here: https://github.com/wasmgroundup/emit

pdubroy··on WebAssembly from the Ground Up
Hi HN! Co-author of the book here, happy to answer any questions you have.

Beyond the sample chapters which are linked from the landing page, we also have a couple blog posts which may be interesting:

- A WebAssembly Interpreter: https://wasmgroundup.com/blog/wasm-vm-part-1/

- An older blog post, "A WebAssembly compiler that fits in a tweet" (https://wasmgroundup.com/blog/wasm-compiler-in-a-tweet), was also on HN earlier this year: https://news.ycombinator.com/item?id=42814948

pdubroy··on Garbage collection is useful
It's explained in the post:

> Then, my plan was to construct a ProseMirror transaction that would turn the old tree into the new one. To do that, it’s helpful to know which nodes appeared in the old document, but not the new one.

So, it's not actually about reclaiming the memory. It's about taking some action on the nodes that will be reclaimed. It's akin to a destructor/finalizer, but I need that to happen synchronously at a time that I control. JavaScript does now support finalization (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...) but it can't be relied on to actually happen, which makes it useless in this scenario.

pdubroy··on Garbage collection is useful
I think you're skipping over some important distinctions here.

In a mark & sweep GC, the mark phase traverses the object graph, visiting only live objects. You need to recursively visit any objects that are not already marked — this is the process known as tracing. The marking time is proportional to the number of live objects.

In the sweep phase, you typically do a linear traversal of memory and reclaim any objects that are not marked. You do not examine pointers inside any objects, so the graph structure is irrelevant. The time is proportional to the total size of memory.

In reference counting, when a refcount hits 0, you need to decrement the refcount of pointed-to objects, and recursively visit any objects whose refcount is now 0. The time is proportional to the number of objects that have just died.

Structurally, decrementing refcounts is *very* similar to tracing. You're right that it's purpose is similar to the sweep phase of a mark & sweep GC, but they aren't algorithmically similar.

pdubroy··on Garbage collection is useful
(OP here) It’s possible, but I doubt it. Perhaps the way I wrote it makes it sound like I was thinking about it as a GC problem from the beginning, but I wasn’t. It wasn’t until I started seeing it as as being like GC that (a) I realized that my naive solution was akin to tracing GC, and (b) I came up with the reference counting solution.
pdubroy··on Ohm Editor
Hi HN! I'm the main author of the Ohm Editor, and co-creator and primary maintainer of Ohm itself.

Ohm is a user-friendly parsing toolkit for JavaScript/TypeScript. You can find out more at https://ohmjs.org.

Anyone interested in the editor might like to check out a blog post I wrote about it a few years ago called "Visualizing Packrat Parsing" (https://dubroy.com/blog/visualizing-packrat-parsing/)

Some people also might be interested our book WebAssembly from the Ground Up (https://wasmgroundup.com): you can learn Wasm by building a simple compiler in JavaScript, using Ohm.

pdubroy··on WASM 3.0 Completed
Folks here might be interested in WebAssembly from the Ground Up (https://wasmgroundup.com) — an online book to learn Wasm by building a simple compiler in JavaScript. (Disclaimer: I'm one of the authors.)

So far the book only covers WebAssembly 1.0 though. We'll likely publish an update to cover the (few) new features in 2.0, but WebAssembly 3.0 is a pretty big update. Garbage collection and typed references especially add quite a lot to the spec. But, they also make a lot more things possible, which is great.

The spec itself is also very readable and accessible. Everything in the spec that's described formally is also described in plain language. I can't think of any other spec that's quite as nice to read.

pdubroy··on WASM 2.0
Ah, I see! Yeah that's significantly trickier.

re: "dynamically replace parts of the implementation as source code evolves" — there is a technique for this, I have a short write-up on it here: https://github.com/pdubroy/til/blob/main/wasm/2024-02-22-Run...

About the debugging and inspecting —

Inspecting Wasm memory is easy from JS, but to be able to do the debugging, you'd probably either need to rewrite the bytecode (e.g., inserting a call out to JS between every "real" instruction) or a self-hosted interpreter like wasm3 (https://github.com/wasm3/wasm3).

(Or maybe there are better solutions that I'm not thinking of.)

pdubroy··on WASM 2.0
I'm not sure I totally understand what you mean by "in-process" here. But you could have some JavaScript that compiles some code in your custom language to WebAssembly and then execute it, and you can use the browser dev tools to set breakpoints the Wasm, inspect the memory, etc.

In the book, we don't cover source maps, but it would also be possible to generate source maps so that you can set breakpoints in (and step through) the original source code in your custom language, rather than debugging at the Wasm instruction level.

Does that answer your question?

pdubroy··on WASM 2.0
The WebAssembly spec is quite approachable, but for anyone who is interested in learning Wasm and doesn't want to read the spec —

WebAssembly from the Ground Up (https://wasmgroundup.com/) an online book to learn Wasm by building a simple compiler in JavaScript. It starts with handcrafting bytecodes in JS, and then slowly builds up a simple programming language that compiles to Wasm.

There's a free sample available: https://wasmgroundup.com/book/contents-sample/

(Disclaimer: I'm one of the authors)

pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
I found some benchmarks in the ANTLR project: https://github.com/antlr/grammars-v4/blob/master/java/java/B...

  Project          Parsing/Lexing Ratio
  ----------------------------------------
  jdk8               5.34x
  Spring Framework   3.81x
  Elasticsearch      5.76x
  RxJava             5.69x
  JUnit4             4.51x
  Guava              5.37x
  Log4j              2.92x
Obviously this is just one toolkit, one language, and one set of examples. But in these benchmarks, the tokenization (lexing) time is a small fraction of the total parse time.
pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
Yes, you're right that PEG parsing is usually not the fastest option. As with many things, the operative question is: is it fast _enough_?

> Note that this includes the time for tokenization, which is generally the bulk of the time spent in parsing

Hmmm, I've never heard this before and I'm curious if you can point me to any benchmarks or other sources that demonstrate this. If it's true it's surprising to me!

pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
It's worth noting that Python 3 uses a PEG-based parser and its performance (when it was introduced at least) was within 10% of the old parser: https://peps.python.org/pep-0617/
pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
Oh, that sounds cool! Are you on the Ohm Discord? I'd love to hear a bit more about this project :)
pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
Maintainer of Ohm here :)

The main difference in Ohm grammars vs "standard" PEGs is support for left recursion. It's the same approach that was used in OMeta, which is described in the paper "Packrat parsers can support left recursion": https://web.cs.ucla.edu/~todd/research/pepm08.pdf

The other thing Ohm does that's different from many PEG parsing libraries is a strict separation of syntax and semantics. Many PEG tools mix these two concepts, so you write little snippets of code (semantic actions) alongside the rules.

pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
Very close! Alex Warth created OMeta (https://en.wikipedia.org/wiki/OMeta) as part of the STEPS project. Ohm was designed as a kind of successor to OMeta, but was created after STEPS.
pdubroy··on Ohm: A user-friendly parsing toolkit for JavaScript and TypeScript
Thanks for the kind words :)

I also wrote a blog post about some of the decisions that went into the visualizer: https://dubroy.com/blog/visualizing-packrat-parsing/

pdubroy··on Five coding hats
Hey, author here! Yes, that's how I see it as well.
pdubroy··on I Wrote a WebAssembly VM in C
Glad to hear!

If you haven't looked at it in a while — we just published a draft of the final technical chapter, and are planning an official launch on March 4. So, might be a good time to dig back in :-)

pdubroy··on I Wrote a WebAssembly VM in C
You should check out the book :-)

We have a chapter called "What Makes WebAssembly Safe?" which covers the details. You can get a sneak peek here: https://bsky.app/profile/wasmgroundup.com/post/3lh2e4eiwnm2p

pdubroy··on I Wrote a WebAssembly VM in C
This is great! The WebAssembly Core Specification is actually quite readable, although some of the language can be a bit intimidating if you're not used to reading programming language papers.

If anyone is looking for a slightly more accessible way to learn WebAssembly, you might enjoy WebAssembly from the Ground Up: https://wasmgroundup.com

(Disclaimer: I'm one of the authors)

pdubroy··on A WebAssembly compiler that fits in a tweet
Co-author of the post here — we had 280 characters in mind. :-)
Page 1 of 5Next →