The chapter 5 of Crafting Interpreters has been published and after a first read I started writing some Swift code to continue my implementation of the interpreter. Here there are some thoughts that I've captured while implementing the Expression classes.
As I wrote in the first post, and in the README of the project, I want to follow closely the Java implementation in order to don't get sidetracked and end up with a different beast and ultimately lose motivation. But with this chapter the diferences between Java and Swift start becoming a little frustrating.
In this chapter the book makes a small tool to generate Java code for the Expression classes. This is necessary because writting those simple classes in Java requires a lot of boilerplate. I started doing the same just for fun, I like implementing small scripts in Swift to keep tasting the it as a scripting langauge.
The script doesn't have anything special but it could be easier. I would love for Swift to become better at this kind of metaprogramming. It would have been amazing to be able to writte a shorter amount of code in the main project itself and let the compiler generate the code. Another good option would have been the use of some templating engine to replace the necessity of building the String manually.
The outpit itself, is not nice Swift. Java uses an abstract class, a concept that doesn't exist in Swift, so I ended up using the old trick of crashing at runtime if the method is not overwritten. Not pretty but does the job.
Another small detail is that the original code has the
Visitor interface nested inside the
Expr class which provides a sort of namespace that I think is quite nice. But Swift seems to not like having protocols nested in classes so I had to move it into the global namespace.
Even with these drawbacks I wrote the generator and the AST Printer using the classes and the Visitor pattern. But not without keeping notes on all this things, notes that you see reflected now in this post. But I also had some notes for things to experiment with.
The abstract classs can be obviously replaced with a Protocol and some extensions if required, specially while it doesn't contain any storage (which Swift still can retroactively add using extensions). But for me hearing AST screams to Swift enums with associated values.
One of the reasons why I didn't go there from the start is because I've seen some people going down that path for this kind of case and ending up undoing it because enums didn't scale quite well. For now I have an experimental branch with the
Expr being an enum and the ASTPrinter using it without any problem. I can see how Swift enums with associated values, pattern mathing and extensions can be a nice way of solving the Expression Problem mentioned in the book. I don't plan to keep the experimental branch up to date, it will get difficult with more code, but for now it has been a nice way of experimenting.
Can't wait for the next chapter.