Breaking Dependencies - The Visitor Design Pattern in Cpp - Klaus Iglberger - CppCon 2022

preview_player
Показать описание
---

Breaking Dependencies - The Visitor Design Pattern in C++ - Klaus Iglberger - CppCon 2022

The extensibility of code with new functionality is essential for long-term maintenance of a code base. However, when using dynamic polymorphism there is always a choice: either easily add types, or easily add operations. For instance, by means of inheritance hierarchies it's easy to add new types, but it's difficult to add new operations.
But there is a common workaround to overcome this weakness: the Visitor design pattern.

In this talk, I’ll explain the design properties of Visitor, including its benefits and shortcomings. I’ll also talk about different kinds of visitors (cyclic and acyclic) and show when to reach for a Visitor and when to avoid it. Additionally, I’ll demonstrate the different implementation strategies (classic and modern) and address their individual benefits and problems.
---

Klaus Iglberger

---

#cppcon #programming #cpp
Рекомендации по теме
Комментарии
Автор

I found that std::variant::visit method in the documentation and was wondering why it might be a good idea to ever use it. After searching around a bit, I found this talk. Very illuminating, I dig this logic and I was always interested in various ways of doing runtime polymorphism.

Alexander_Sannikov
Автор

Klaus Iglberger is definitely my favorite presenter!

StefaNoneD
Автор

Absolutely amazing presentation! Thank you Klaus Iglberger, I really enjoyed watching this and learned a good few things along the way. Do not hesitate to hire this man for training.

russCoding
Автор

In relation to the Acyclic Visitor pattern presented, I believe the Visitor<T> classes could virtually inherit from the empty base AbstractVisitor, and therefore both let operation implementers eschew the extra base and potentially obviate the cross-cast in the accept implementations in favor of a simple downcast.

Can anyone shine some light on any downsides?

Edit: Oops that’s impossible. Have a nice day people

Barfriedrich
Автор

Nice thanks for the talk. I agree visitor works good in some cases.

To be honest though I’ve seen it applied in cases where it makes everything very complex, especially when templates start to become involved.

It seems to suffer a bit from the issue where if you make a new class you then need to update like 10 different spots to fully implement it.

It ends up being a bit similar to having switch statements everywhere for an enum type.

Also the issue where you need to know all the types used in a std::variant beforehand, so can’t extend things from different assemblies without adding a lot of templating.

But as always, time and place 😊

theskydebreuil
Автор

Whether adding types or adding operations, I think it is relatively frequent. Unless you are very sure, it is better to use the most direct method.

verdantblast
Автор

Very good Klaus. Great complement to the type erasure talks. Perhaps would have liked to have seen the overload() idiom for the implementation of the modern visitor, rather than a functor.

oschonrock
Автор

So, visitor is for adding operations and type erasures for adding types easily. What if we combine and apply these two concepts, i.e., apply type erasure on the "visitor" hierarchy part? Or maybe std::variant is doing that?

davithov
Автор

I don't think recompilation in result of touching (6:50) the enum is a disaster. Making change all over the code is much more important though

alexeysubbota
Автор

Since I started working in HPC, whenever I see dynamic polymorphism used on data, I cry inside. I think I need a therapy ...

embeddor
Автор

Author says that with the visitor pattern it is easier to add operations․
My concern is that actually, instead of overriding those functions in derived classes, we create types of these functions (like Rotate, Draw etc.) and when we add a function, we need to introduce new type like, e.g., Serialize. But this is not enough actually: we have to also override ALL visit functions in that class. So, what is the difference between overriding visit functions and Serialize function in a derived classes? In any case in both cases we have to override K functions (either visit or a function) if there are K operations.
Although I understand that we actually might break dependencies from 3rd parties in our actual concrete class (like Circle, Square etc.). For example, if there is a 3rd party tool which helps to draw, then Circle won't know anything about that library. Instead, concrete visitor will know about it, hence we avoid introducing dependencies from 3rd party library for the concrete types (Shapes). I mean this is I understand and accept, but how we make easier adding functions: that part I don't understand well.

davithov
Автор

I'm hoping that the issue is actually resolved in this talk, but at 11:30ish the issue of having to touch the base class to add more operations... visitor (as far as i know) has the same limitation

StevenMartinGuitar
Автор

Gotta love when people go the long way around and end up with the obvious tagged union approach that we've had since forever. If you're thinking about Object-Oriented Programming and patterns and what's theoretically going to be a good design, you're doing it wrong. You should be thinking about more fundamental ideas like performance, decoupling, systematization, minimalism, etc., and always in the context of solving a concrete problem. The code will tell you what needs to happen to it over time if you listen.

rationalcoder
Автор

how does this compare to using components?

perfectionbox
Автор

when we're talking about the downsides of visitors, are we going to just keep ignoring the elephant in the room -- the huge dedicated class with a bunch of operator()'s declared for every type? rust and zig do the same exact thing on the language level with no syntactic overhead using tagged enum pattern matching. it's literally the same thing on the lowest level, you just don't have to write a whole bunch of garbage boilerplate code like intermediate classes with operators that makes it happen.

Alexander_Sannikov
Автор

looks all nice on paper but i rather debug a switch statement with a type instead of a std::visit on a variant. std::visit looks only good until u actually use it. imo std::visit was a mistake and is just a very very horrible compensation for not having pattern matching

thomasziereis
Автор

We need a new word! Let's call it 'auto procedural programming'.

jknight
Автор

21:38, you don't need them, you need a dynamic static array, at the start before you ever use the class you register the classes in use along with their callbacks, you then can have the global visit() etc functions use take registered IDs to identify where in the array to select the actual function from, you destroy the array only at the exit of the program. Still, looking at what you've shown so far it seems the c++ community is taking the long route to learning C is better for control, despite it lack of the awkward semantics you lot introduce to your extension of the language it ends up being both easier to understand and easier to adapt, I can only sit amused by how long you're taking to re-learn what programmers in the early days learnt without fuss. Even I who was just a teenager when I first dabbled in programming realised quickly that C gave me everything I wanted after I learned how inflexible object oriented programming and a lack of types was via javascript

zxuiji
Автор

For me I don’t really see a benefit. This seems like the kind of thing you end up implementing to duct tape a solution together for a codebase that has lived for way too long and or grown too big.

ckjdinnj
Автор

So with the visitor - something changes aaaand now what?
How to make sure that all new shapes implement all the needed functions?
You also limit your self and the compiler to the public interfaces.
More complexity will tend to reduce performance of the visitor pattern - at least we have seen that several time sin our codebase and while the local code is easier to read understanding what is happening exactly became harder.

But in general I am trying to push the code in that direction cause the computations them self are several orders of magnitude faster than other parts of the system and it would help with getting new guys to understand the system.

ABaumstumpf
welcome to shbcf.ru