Live data from Hacker News

Crafting Interpreters

craftinginterpreters.com

161–170 of 193 posts

Re: Crafting Interpreters

#161

Author here. Seeing all of the positive comments about my book is really warming my heart. I appreciate everyone and I'm glad so many people have enjoyed the book. I put a ton of time and love into it and it's gratifying to see it had the effect I'd hoped for.

That book is an absolute treasure and you should be proud.

At a personal level, this book contained so much that I had always wanted to know, from how hashmaps work, to how to compile in a single pass. And I connected with your note on getting into writing languages partly due to a feeling of being less-than programmers who could create their own language.

One thing I wanted to share: I found a small design change to Clox that eliminates an entire class of hard-to-debug GC bugs.

Basically, the change is that garbage collection never occurs during the execution of an instruction.

Instead, garbage collection is an instruction which is never emitted by the compiler. When the heap size crosses the garbage collection threshold, we schedule a garbage collection, which will occur after the current instruction is done executing, and before the next instruction executes.

To implement this, in the Self-Adjusting Heap[1] section, we set a global variable (let's call it "resume pointer") to the next instruction, similar to the return pointer in a call frame. Then we set the instruction pointer to point to a global constant which contains only the garbage collection instruction.

The way this works: let's say the current instruction allocates something, and the allocation needs to trigger a GC. To trigger the GC, we set the resume pointer to the next instruction, and the instruction pointer to the global constant garbage collection instruction (let's call this GCGCI). When the current instruction completes, the VM goes to the instruction pointer to get the next instruction, and finds it pointing to the GCGCI. It then executes the garbage collection instruction, which runs the garbage collection. The final step of the garbage collection instruction is to set the instruction pointer to the resume pointer (similar to a return pointer) so that when the VM goes to execute the next instruction it resumes the execution of the user program right where it left off.

This adds a bit of performance overhead to garbage collection, but I would guess we more than get it back from the fact that it's no longer necessary to temporarily push objects onto the stack to prevent them from getting GCed mid-instruction. And this eliminates that entire class of GC bugs; code stability and programmer time are worth something!

An alternative implementation might observe that the resume pointer is basically a return pointer, so you could potentially store this on the call stack. I didn't really think through the pros and cons of this as it seemed like just adding a global resume pointer solved the problem more simply. However, one thing I was working on is making my interpreter multithreaded, and this means that most of the global variables used by the VM get stuffed into a "Thread" struct. Keeping the size of this thread struct low is a high priority because that memory usage is a limiting factor in the number of threads you can reasonably run simultaneously, so in this case moving the resume pointer onto the call stack starts to look like a bigger benefit.

[1] https://craftinginterpreters.com/garbage-collection.html#sel...

Re: Crafting Interpreters

#162
post #148

Earlier quoted context omitted.

It’s had pattern matching since 16, it’s been expanded since with some syntactic sugar and more recently the introduction of sum types and exhaustiveness to go along with pattern matching.

IMO Java's pattern matching is still fairly primitive. Not even up to the level of usefulness of Scala 2.13.

Interesting - what specifically is missing? I’m thinking we’ve got all of scala’s pattern matching since JEP 406 (2021) but I don’t write Scala so there’s maybe a feature i don’t know. Would be interested to know.

    switch (thing) {
        case Integer i when i > 0 -> println(“Positive…”);
        case …
    }

Re: Crafting Interpreters

#163

Earlier quoted context omitted.

That brings back some memories... Having just started learning Java I wanted to create my own language. It wasn't that bad, I even managed to implement an operator precedence algorithm without looking it up. It worked by scanning the list of tokens and each time finding the highest priority subexpression. There was no recursion involved, just good old manual pushing and popping on a stack. The problem was that I didn…

what do you mean by some concepts not being nestable?

From what I remember, variable references started with a dollar sign and you'd need to apply a new level of escaping (another dollar sign) to variable names with each inner loop, otherwise the variables would be substituted once and kept for all loop iterations. You can sometimes see similar issues in shell scripts, the following command prints three empty lines instead of numbers: sh -c "for i in 1 2 3; do echo $i; done"

There were countless other restrictions too, some expressions could only take a variable name. Statements were delimited by lines (and optionally also by semicolons) so any loop or conditional, regardless of nesting depth, had to fit inside a single line. Due to usage of string.split, initially all semicolons had to have a space before them, I remember feeling very smart when I added automatic splitting of "abc;" into two tokens "abc" and ";"

Re: Crafting Interpreters

#164

Author here. Seeing all of the positive comments about my book is really warming my heart. I appreciate everyone and I'm glad so many people have enjoyed the book. I put a ton of time and love into it and it's gratifying to see it had the effect I'd hoped for.

Thank you for putting the time into writing it! Your book was what really made it all click for me, and I'm currently working on my own static-type compiled language as a result. I plan on doing part 2 of your book in that language; it's going to be so horrific!

Re: Crafting Interpreters

#165

Author here. Seeing all of the positive comments about my book is really warming my heart. I appreciate everyone and I'm glad so many people have enjoyed the book. I put a ton of time and love into it and it's gratifying to see it had the effect I'd hoped for.

Hi Bob, I haven’t completed the book yet, but I wanted to note I appreciate you making it available for free online. I do my best to support authors like you (I have the book in print, PDF, and Kindle editions) and encourage others to do the same. Thank you!

Re: Crafting Interpreters

#166

Read Crafting Interpreters when building Crumb ( https://github.com/liam-ilan/crumb ). It was indispensable, especially the sections on scope and local variables. The balance between technical implementation and conceptual insights is super helpful, especially when trying to go off of the book’s set path. It’s inspiring to see technical writing done like this. As an aspiring engineer, this sets a really high standard…

> Aspiring engineer

You already made it, no need to be humble. You don’t need to finish the CS to call yourself engineer :)

Great documentation and an awesome project. Good job.

Re: Crafting Interpreters

#167
I love this book, it's an excellent and refreshingly readable complement to more academic texts. I recommend pairing with Friedman's "Essentials of Programming Language". While I also love the Friedman, it's nice to read some PLT without feeling like I got punched in the face sometimes... ;-)

Re: Crafting Interpreters

#168

Author here. Seeing all of the positive comments about my book is really warming my heart. I appreciate everyone and I'm glad so many people have enjoyed the book. I put a ton of time and love into it and it's gratifying to see it had the effect I'd hoped for.

Would you be interested by translations? I can do it in French and Esperanto.

And by the way, thank you very much for the original version.

Re: Crafting Interpreters

#169

Earlier quoted context omitted.

> Doing it the other way is a common pitfall in teaching programming concepts. 100% disagree If someone is brand new to programming and you're expecting to teach them the following concepts: A class, methods, static methods, data types, method return types, void return type, arrays, and namespaces just to be able to write a simple "Hello World" app [1] I think your approach is the one that's misguided. The most commo…

You say 100% disagree, but then everything you say seems to agree with my points. I would even go so far as to endorse your response as a longer form elaboration of exactly what I was trying to get across.

I see you claim that, but unless I misunderstanding that completely contradicts our claim here:

> A very common example is the historically necessary boilerplate in Java’s Hello World, where quite a few concepts are present but handwaved away as you don’t need to worry about this now.

What I'm saying is exactly that. Handwave past all of the boilerplate like the static declaration and only focus on the most important to learn up front (ex what a string is).

Could you explain how your statement of initially teching the boilerplate is the same as my statement of ignoring it?

In my example, the entire time they are working with strings or readline/writeline method calls they are entirely ignoring what a static/class/args all mean and they are just boiler plate they have to type until they get to that stage in later lessons.

Re: Crafting Interpreters

#170

Earlier quoted context omitted.

You say 100% disagree, but then everything you say seems to agree with my points. I would even go so far as to endorse your response as a longer form elaboration of exactly what I was trying to get across.

I see you claim that, but unless I misunderstanding that completely contradicts our claim here: > A very common example is the historically necessary boilerplate in Java’s Hello World, where quite a few concepts are present but handwaved away as you don’t need to worry about this now. What I'm saying is exactly that. Handwave past all of the boilerplate like the static declaration and only focus on the most important…

> Could you explain how your statement of initially teching the boilerplate is the same as my statement of ignoring it?

I specifically said that including the boilerplate is a common pitfall, and requires teaching around a bunch of impertinent concepts.

I also chose the example for a reason very close to your example with Racket: later versions of Java have similarly aimed to reduce the necessary boilerplate. And if I’m not mistaken, the learning experience is a motivating factor for that as well.

If emphatically agreeing with you in so many words isn’t enough to convince you that I agree with you, maybe you’re just looking for something to argue about?

Post reply on HN