 Do people in 2022 really use design patterns? What's the point of using design patterns when we have modern programming languages like Rust and TypeScript? Let's look at some real uses of a visitor design pattern. I mean, it must be crusty old Java code, right? The first example we're gonna look at is Google Chrome. In Chromium, there's a zoom feature where you can zoom in and out using the keyboard or mouse. If in Google Chrome, you zoom in on a webpage, it zooms in and out at all open tabs and windows you have for that domain. How does that work? Well, there are three parts. First part, code runs when we click the button to zoom. This code creates a render view zoomer that calls for reach on the render views. Render view refers to a window in Chrome, a window or tab. Second part is our visitor. Render view zoomer inherits from render view visitor and there is a virtual function visits. What does visit do? The visitor will call set zoom level on each window if the domain matches the zoomed tab. How does it go through every view and run that code? The third part of this pattern is the object structure. In this case, it's this for each function. The for each function takes in the zoomer and the zoomer does the work of zooming. The render view for each is pretty basic. It loops through every view and runs the visit function. Now here we separated looping functionality from what we do with each render view, which means we can do other things. This code uses render view for reach to collect all of the views associated with an extension. So here we have some views open for an extension you block origin. When we uninstall the extension, the tab closes and the window disappears. So why did we use a visitor? We're able to use the same code of looping over the views for multiple purposes. In one case, we change the zoom level of all the different tabs. And in another case, we close the tabs. What could the authors of this code have done instead? The authors could have exposed the list of render views. However, this would break encapsulation. They could have added methods to the render view class. However, this would put code in the wrong spot and it wouldn't be extensible. They could have also used the iterator pattern. And I think the iterator pattern would have been 100% okay. However, implementing the iterator pattern in C++ is a little complicated. So the visitor pattern is a bit easier to implement. You may have seen for reach in other programming languages such as JavaScript, and that does implement part of the visitor pattern. It's just a very small application of the visitor pattern. So small, you don't even notice that it's a special pattern. Sometimes design patterns are just there even though you don't notice them. Let's look at another example, this time on a website. Here we have a webpage. This is generated from Markdown code. We wanna make this prettier by adding a link in the heading and we also wanna indent the code blocks and we want to highlight the error in the code right here. So how do we do that? In order to convert the code into HTML, we use a library to convert the parsed Markdown into HTML. Now by default, the render function generates HTML but we wanna customize the HTML. To do that, we override a bunch of the rules such as the heading open and heading close rules. Here we customize the HTML by adding a hyperlink that refers to itself. For the code blocks, we do a bunch of shenanigans to inject Mark elements into the HTML and finally we wrap it in a figure. The end result is a linkified header and error squigglies in the documentation. Now here again are three parts to the visitor pattern. There is the visitor itself, which are the rules that are defined by the library but we customized. There's the code orchestrating the whole thing and finally there's the code calling the visitor, which is part of the Markdown library. Now why did we use the visitor pattern here? Well, it let us reuse the HTML generation code in the Markdown library and it let us easily walk a tree structure and edits individual pieces of the tree structure without us using recursion or a loop ourselves. What could we have done instead? We could have exposed a tree structure but that would mean walking the tree is cumbersome. We have to recurse and we can't easily reuse the HTML generator that the library provided. We could have used the iterator pattern but the iterator pattern does a bad job of iterating through trees. And we could have generated HTML and modified the HTML after the fact but that's error prone and often slower than generating the correct HTML in the first place. Let's look at a third application, which is the FD tool. The FD tool looks for files in the file system. Here you can see its default output which is to walk the file system and prints file by file and when it encounters a directory print the files inside the directory recursively. Now how does it do this? The FD tool uses the ignore library. The ignore crate provides a walk parallel struct that serves as the object structure. What it does is it scans the file system, looks for files and reports the files it finds to the visitor. Here we have a parallel walker and we're giving it a visitor in the form of an anonymous function. The previous examples we gave a class or an object here we're giving an anonymous function because there's only one callback. The function gets called for every file, it does a bunch of filtering and eventually, eventually, eventually it sends the results off to a different thread so that it can be presented in order. Now one major advantage of this approach is that it can be parallelized. It's very hard to parallelize iteration using the iterator pattern but with a visitor pattern it is relatively trivial. Another advantage of the visitor pattern we can prude trees very easily by returning different return values signaling that we need to skip the subtree or continue going and descending into the directory. If you're interested in more design patterns check out my playlist on design patterns and practice.