https://craftinginterpreters.com/representing-code.html#the-...
I remember reading through it and not understanding why it had to be this complicated and then just used a tagged union instead.
Maybe I'm too stupid for OO. But I think that's kind of the point of the grug article as well. Why burden ourselves with indirection and complexity when there's a more straight forward way?
https://prog2.de/book/sec-java-expr-problem.html - Not the writeup I was looking for but seems to cover it well.
> Why burden ourselves with indirection and complexity when there's a more straight forward way?
Because each way has its own tradeoffs that make it more or less difficult to use in particular circumstances.
https://homepages.inf.ed.ac.uk/wadler/papers/expression/expr... - Wadler's description of the expression problem.
https://grugbrain.dev/#grug-on-parsing
but the visitor pattern is nearly always a bad idea IMO: you should just encode the operation in the tree if you control it or create a recursive function that manually dispatches on the argument type if you don't
However, this is just not something that I typically perceive as a problem. For example in the book that I mentioned above, I didn't feel the need to use it at all. I just added the fields or the functions that were required.
In the first link you provided, the OCaml code seems to use unions as well (I don't know the language). I assume OCaml checks for exhaustive matching, so it seems extremely straight forward to extend this code.
On the other hand I have absolutely no issues with a big switch case in a more simple language. I just had a look at the code I wrote quite a while ago and it looks fine.
In languages influenced by ML (like contemporary Java!) it is common in compiler work in that you might have an AST or similar kind of structure and you end up writing a lot of functions that use pattern matching like
switch(node) {
type1(a,b) -> whatever(a,b)
type2(c) -> process(c)
}
to implement various "functions" such as rewriting the AST into bytecode, building a symbol table, or something. In some cases you could turn this inside out and put a bunch of methods on a bunch of classes that do various things for each kind of node but if you use pattern matching you can neatly group together all the code that does the same thing to all the different objects rather than forcing that code to be spread out on a bunch of different objects.https://blog.scottlogic.com/2025/01/20/algebraic-data-types-...
Stands to reason. Rust "enums" are tagged unions (a.k.a. sum types, discriminated unions).
In implementation, the tag, unless otherwise specified, is produced by an enum, which I guess is why it got that somewhat confusing keyword.
The additional complexity doesn't add significant value IMO. I admit that's a subjective claim.