4 ms·
For the record, this design pattern is called a virtual method table, or vtable. I'm surprised that this article never mentioned the term. C++ programmers wil
by cbarrick 2y ago
For the record, this design pattern is called a virtual method table, or vtable.
I'm surprised that this article never mentioned the term.
C++ programmers will know this pattern from the `virtual` keyword.
- rzzzt 2y agoYou can take it a step further: - instead of setting the same function pointers on structs over and over again, point to a shared (singleton) struct named "vtable" which keeps track of all function pointers for this "type" of structs - create a factory function that allocates memory for the struct, initializes fields ("vtable" included), let's call it a "constructor" - make sure all function signatures in the shared struct start with a pointer to the original struct as the first parameter, a good name for this argument would be "this" - encode parameter types in the function name to support overloading, e.g. "func1_int_int" - call functions in the form of "obj->vtable->func1_int_int(obj, param1, param2)"
- drivebyhooting 2y agoIs this satire? That’s almost exactly the C++ way.
- relistan 2y agoIt’s not satire, it’s how you do full OO in plain C.
- actionfromafar 2y agoIt's overloaded - it is satire, but also, it isn't.
- rzzzt 2y agoExactly. Thank you for your time, I will and won't be here all week!
- procaryote 2y agoSome say C++ is satire
- p_l 2y agoIt's how you do it in many C++ implementations, but IIRC it's not actually mandated in any way unless you strive for GCC's IA-64 ABI compatibility (the effective standard on Linux for C++) C++'s vtables are also, in my experience, especially bad compared to Objective-C or COM ones (MSVC btw generates vtables specifically aligned for use with COM, IIRC). Mind you it's been 15 years since I touched that part of crazy.
- pjmlp 2y agoIt is more the other way around, COM was designed to fit with how MSVC generates vtables. It is a simplification of OLE, and by the time the idea came up to use that approach, there were tons of OLE code since Windows 3.1. By the way it wasn't gone away, after how Longhorn went down, it became the main API delivery mechanism on Windows, sadly improving the tooling has never been a pritority other than half-finished attempts.
- magicalhippo 2y agoThis is pretty much how you do COM[1] in C[2]. [1]: https://learn.microsoft.com/en-us/windows/win32/com/com-technical-overview https://learn.microsoft.com/en-us/windows/win32/com/com-tech... [2]: https://www.codeproject.com/Articles/13601/COM-in-plain-C https://www.codeproject.com/Articles/13601/COM-in-plain-C
- starspangled 2y ago> You can take it a step further: No, that is essentially what Linux does in this article (and by the looks of it also ffmpeg). struct file does not have a bunch of pointers to functions, it has a pointer to a struct file_operations, and that is set to a (usually / always?) const global struct defined by a filesystem. As you can see, the function types of the pointers in that file_operations struct take a struct file pointer as the first argument. This is not a hard and fast rule in Linux, arguments even to such ops structures are normally added as required not just-in-case (in part because ABI stability is not a high priority). Also the name is not mangled like that because it would be silly. But otherwise that's what these are, a "real" vtable. Surely this kind of thing came before C++ or the name vtable? The Unix V4 source code contains a pointers to functions (one in file name lookup code, even) (though not in a struct but passed as an argument). "Object oriented" languages and techniques must have first congealed out of existing practices with earlier languages, you would think.
- rzzzt 2y agoThe proto-C++ transpiler used C with this and similar techniques behind the scenes: https://en.wikipedia.org/wiki/Cfront https://en.wikipedia.org/wiki/Cfront
- chrsw 2y agoI've noticed many large C projects resort to these sorts of OOP-like patterns to manage the complexity of the design and size of the code base. But I'm not aware of any one standard way of doing this in C. It seems C++ standardized a lot of these concepts, or C++ developers adopted standard patterns somehow.
- jcelerier 2y agoand C++ also supports optimizing them, especially when you use `final` keyword and LTO which is able to devirtualize at the scale of a whole program.
- i_am_a_peasant 2y agoInteresting, in Rust those optimizations are more implicit since there's no "final" keyword when you use dynamic dispatch via trait objects. + you also got LTO. I wonder if there are many cases where C++ will devirtualize and Rust won't. But then again Rust devs are more likely to use static dispatch via generics if performance is critical.
- tialaramex 2y ago> But then again Rust devs are more likely to use static dispatch via generics if performance is critical. Put another way, in C++ the dynamic dispatch is implicit, so you might write code which (read literally) has dynamic dispatch but the optimizer will devirtualize it. However in Rust dynamic dispatch is explicit, so, you just would not write the dynamic dispatch - it's not really relevant whether an optimizer would "fix" that if you went out of your way to get it wrong. It's an idiomatic difference I'd say.
- pornel 2y agoIn Rust objects can dynamically go in and out of having virtual dispatch. The vtable is only in the pointer to the object, so you can add or remove it. Take a non-virtual object, lend it temporarily as a dynamically dispatched object, and then go back to using it directly as a concrete type, without reallocating anything. That's pretty powerful: • any type can be used in dynamic contexts, e.g. implement Debug print for an int or a Point, without paying cost of a vtable for each instance. • you don't rely on, and don't fight, devirtualization. You can decide to selectively use dynamic dispatch in some places to reduce code size, without committing to it everywhere. • you can write your own trait with your own virtual methods for a foreign type, and the type doesn't have to opt-in to this.
- trelane 2y agoI learned it from a textbook. I think it was an earlier printing of https://docs.freebsd.org/en/books/design-44bsd/ https://docs.freebsd.org/en/books/design-44bsd/