Design Patterns Are Temporary, Language Features Are Forever
Design patterns are these cool things that make you go ‘hell yeah’ because they make a certain problem easier to deal with. Whether it’s applicable to all languages, or due to a language constraint, they’re pretty nice. Of course, some people go crazy with them rather than doing the simple thing that works. Other times, you’ll naturally do a design pattern without even knowing about it.
Every once in a while, I like to go through design patterns that are ‘commonly applicable’ to Java as a thought experiment to see:
- Have I seen this in a codebase before?
- Does this look like something that would’ve helped me with before?
- Is this a solution to a problem which doesn’t exist?
and so on.
A few times I have come across patterns such as ‘visitor’ and never truly grasped what it was solving, or why I would use it. Young Joel was unsure, probably due to poor explanations, which I think can be a big problem when it comes to concepts today. In jiujitsu, it’s extremely evident when a concept or a technique is practical and not bullshido (if you go to a gym which competes at least in my anecdotal experience). But for the visitor pattern, explanations to me have always been:
“here’s how the pattern works”
just randomly logs stuff
Not exactly helpful presenting how to use ‘x’ with an unrealistic use case.
When my son was born, I had decided to learn Rust since I was sleepless most of the time and I wanted to keep myself sharp during parental leave.
Can you imagine how mind blown I was when I saw this??:
And that’s how Young Joel discovered pattern matching (and further exploration into FP (OCaml btw)).
After some time, I went back to the visitor pattern out of curiosity again to see if I could try to understand it once more. Now knowing about pattern matching, this is how I came to realise that the visitor pattern was pattern matching in an OO way. Of course, it’s not 1:1 (I think), but it gives a familiar feel. I wouldn’t try to pretend I understand completely the key details/downfalls of visitors, but now I had a better idea on how to use them.
At work I write a mix of Java, JavaScript, and Rust. Majority of my time is Java, but I don’t like staying on a particular version for long because that’s a major L and one of the worst characteristics of Java culture today in enterprise land.
The release of Java 21 saw a lot of fantastic features, one of them being: Pattern Matching for switch.
With pattern matching in switches and sealed types, the visitor pattern to me looks like a thing of the past (which is good!). I think if a language can improve in such a way, then the language itself becomes more enjoyable to use. For example, you can do this!:
Here is the Rust version:
Sealed types, records, switch expressions, switch pattern matching.. the list goes on. I really love modern Java, and the feature delivery is quality. Compared to Java <17 it feels like an entirely different language.
Coming back to the visitor pattern, here is some sample code I wrote during my son’s nap times to get a feel on the pattern.
- We model a filesystem where there is a Node which is either a BlobNode or a TreeNode.
- There are two use cases: adding or deleting a BlobNode (the visitor pattern really shines because of how you can implement this)
Here’s it in action:
Honestly it’s pretty cool you can achieve this, but still, for me:
- Lots of code indirection (more use cases or concrete implementations might be harder to comprehend)
- Double dispatch
- New use case requires more ‘visit’ implementations (visit kinda sucks as a term as well)
The only valid point I think is double dispatch, the rest are just opinions.
Here’s the modern Java version:
This even fits entirely on my screen:
In this example, it’s a lot nicer to follow and shifts the idea on being explicitly ‘OO’ to being more on the data itself.
Here’s a side by side:
Visitors feel like an esoteric pattern I think, but now I have more appreciation for them.
Hopefully I’ll never have to work on old Java projects but I got something up my sleeve now if I must.