dave reid

blog

Writing an Interpreter in Go - Book Review

This weekend I finally finished and implemented the book ‘Writing an Interpreter in Go’ by Thorsten Ball. But I did it in Rust. It was my first ‘big’ project in the language and seeing as I haven’t actually written a line of Go before, it was an interesting challenge of trying to convert it over.

I chose the book because I am a huge fan of Thorsten in general. I find a lot of what he shares online incredibly interesting and it has both broadened and deepened my knowledge of programming. His weekly newsletter Register Spill, is one of the few newsletters in my inbox that I actually create the time to read. So I knew that I would enjoy the writing style of the book if it followed suit and it completely lived up to my expectations.

You will go through each stage of building an interpreter in a ‘brick by brick’ fashion until you eventually end up with the whole house. I feel Thorsten does a fantastic job at pacing you through a particular topic by sharing the right amount of information at the right time. Having relatively minimal experience on how an interpreter works, I felt like I was having a light-bulb moment as each chapter passed.

The book follows a TDD approach so you will always start each new section with at least one test. As I was porting the code to Rust, I found this extremely helpful because I knew that if I got to the same test state as the book, I was roughly along the right lines. There were a few times throughout the book where I had to backtrack on my implementation and rearchitect. As you would expect, the tests were a life savour because I knew I just had to keep them green.

The book tends to keeps things pretty minimal but doesn’t skip out on important topics. For example, there are edge cases that won’t be addressed or certain operators that won’t be handled but you will implement closures. I like that though. I think I have enough knowledge now that if I did want to come back and implement some additional functionality, I would know what to do. Two things I wish it did cover are types and generics. Maybe that would be veering away from the minimalist format too much.

All in all, if you want to start your journey into how interpreters work, I would highly recommend this book. It has been a lot of fun to work through and has inspired me to want to carry on learning about the topic. The two things I think I would start with are as follows:

My understanding of Pratt Parsing

The book covers Pratt Parsing in great detail and tries to break down exactly what is happening. I have read over the explanation multiple times and it just won’t fully click for me on what is going on. I think I need to spend some more time on this topic because it is incredibly interesting and I would love to fully comprehend it. I have stumbled across Simple but powerful Pratt Parsing by matklad which on first glance looks great but I haven’t gone through it yet. My plan is to give this a go and see if it unlocks a little more understanding.

General architecture of my implementation

On the whole, although I am proud that I managed to get the interpreter working in Rust, I am still not entirely happy with how the code and architecture panned out. Part of this is obviously down to my current skill level with Rust. Plus the fact I had barely seen Go before, let alone written a line. But something I didn’t appreciate enough was my general ignorance of where the book was heading. I would try to follow the book as closely as possible but what I found is that if one architectural decision works in Go, it doesn’t necessarily mean it works in Rust. This may sound obvious but it caught me out a few times. I had to go back and completely undo decisions because I knew I was going to struggle if I kept going down a particular route. This left the finished code in a state with lots of clones and interior mutability.

The nice thing is though, I have something working and I can always tinker away and try to improve things as my understanding of Rust grows. I already have a few ideas of some improvements I want to implement. For example Oxc have some great learning material on how they structure their JavaScript parser and I am sure there are things I can take from there and apply.

If you want to see my code in it’s current state, it’s available over on Gitlab.

For now though, I am going to get going on Writing A Compiler In Go and see where that takes me!