Hacker News new | ask | show | jobs
by MatheusRich 1464 days ago
The way that worked better for me was doing the book in a different language (I did it in Crystal and Rust). I had to fully understand the intent being every code example so I could translate it correctly.

This adds another layer of difficulty, depending on how comfortable you are with Java and the language of your choice, but it was the way that worked better for me. I truly felt that I created a language, not just copied some code.

4 comments

I also took this approach, and I think it has really helped me understand what I'm doing as opposed to merely transcribing the code.

In my case, I chose to use C++ (more specifically, C++20 under GCC 11) with minimal external dependencies (currently just Boost for memory mapped IO and fmt). I'm working on the second part of the book now (only just getting started, really). My tree-walking interpreter works, but does have some limitations (I currently leak memory in a few locations, such as closures, due to reference-counting cycles).

I've had a few gotchas following along this way, but it's been entirely due to my choices.

One thing I'd highly recommend doing: setup tests to validate your code immediately! I don't have anything fancy setup, but basically what I have is mechanisms to hand a script to my interpreter and capture stdout/stderr. It's not the best level of testing, for sure, but it does allow me to basically place the lox snippets from the book into a reproducible framework to make sure my interpreter is doing what's expected. I also added tracing/memory dump facilities to my tree-walker to facilitate debugging as well (the byte-code interpreter builds this in from the start, so I've not deviated in that aspect, yet).

I'm really enjoying the book. It's definitely created a spark in me I've not felt in quite a while.

Another vote for doing it like this. I chose to learn Haskell by working through this book and they were a perfect match. One thing that really helped was trying to build things using a few different language constructs and seeing which ones worked well and which ones didn't. Really helped me independently arrive at a lot of concepts as I searched around trying to figure out how to make things work (a big one being an understanding of the kinds of ways you need to structure your code for a typesystem like Haskell vs. Java)
I would also vouch for this approach, it's what I did and it helped force me to understand instead of just copying. Honestly, working through this book was the most fun I've had programming in years.

It also helps to have a practical application that you're working towards - I was in the process of building a game server in Node and wanted a way to modify the state at runtime, so I used this book to build an embedded language for debug builds.

Question for you on Rust for part 2. Did you skip the data structure implementations part, did you use unsafe, or did you do shenanigans like Ids instead of pointers with backing vecs to handle them?
I also used Rust, though I only went up to chapter 21 in Part 2. I completely skipped the basic data structure implementations. I had no interest in implementing basic stuff like vectors and hashmaps, because it's not relevant to the problem.

I did go the ID route instead of pointers, because I didn't like the idea of shotgunning the heap with my AST, so I put the actual statements/expressions in vectors and everything else uses indices inside opaque ID types.

For fun, I did also start on doing compiler for part 2 based on the AST from part 1, though as I say, I didn't get far. I got distracted with a static, stack-based, natively compiled language instead.