Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

181–190 of 224 posts

Re: Object-oriented design patterns in C and kernel development

#181
post #121

Earlier quoted context omitted.

What parts of it can't just be compiled as C++ code? (unless it has to do with the subtle difference in implicit lifetime object rules) IMO it's much easier to write resleaks/double-frees with refcounted objects in C than it is in C++

VLAs, named structure assignment, sane treatment of the void type, having different "lifetimes" for object (the C understanding of object) existence and initialization, having different namespaces for composed types and variables, a local error handling convention, leading to better error messages, robuster behaviour and a feeling for completeness, a lot of examples of the article and here in the thread, and most imp…

> named structure assignment

Is a thing since C++20

> sane treatment of the void type

If you're talking about conversion rules, explicit cast from void* to T* makes more sense than implicit since it is a downcast.

> VLAs

IMO these are a mistake (and C++ templates remove a lot of the need for it). They give a false sense of security and invite stack boundary overrun as many people forget to check bounds on these. I found and reported an unauthenticated RCE DoS (crash) in a distributed DB due to VLAs; worse, one cannot always assume the minimum stack size on a system.

> a local error handling convention

Exceptions are problematic in their implementation and how they are (mis)used, but they are supposed to be orthogonal to normal control flow handling, and are not supposed to replace it. They are more-or-less recoverable panics

Re: Object-oriented design patterns in C and kernel development

#182
post #176

Earlier quoted context omitted.

Read the definition again. The programming language here is not the one using this. It is the programmer using it.

Which means that it's not the language doing OOP, but the programmer.

The definition you quoted requires the language to be the one doing it for it to be a vtable. If the programmer is doing it, then it is not a vtable by that definition.

Re: Object-oriented design patterns in C and kernel development

#183
post #120

Earlier quoted context omitted.

> Sorry, but where did you got this definition from? It is from experience with object oriented languages (mainly C++ and Java). Technically, you can do everything manually, but that involves shoehorning things into the OO paradigm that do not naturally fit, like the article author did when he claimed struct file_operations was a vtable when it has ->check_flags(), which would be equivalent to a static member functio…

> handle accesses to that function through the “class”, rather than the “object” You don't need classes for OOP. C++ not putting methods that logically operate on an object, but don't need a pointer to it, into the automatically created vtable, is an optimization and an implementation detail. I don't know why you think that putting this function into a vtable precludes OOP. Wait, how does inheritance work when the me…

The calling convention for C++ non-static member functions always includes a this pointer, even if the function does not use it. Removing it on member functions that do not use it would pose a problem if another class inherited from this class and overrode the function definition with one that did use it. Maybe in very special cases whole program optimization could safely remove the this pointer, but it is questionable whether any compiler author would go through the trouble given that the exception handling would need to know about the change. Outside of whole program optimization, it is unlikely removing this from member functions that do not use it would ever happen because it would break ABI stability.

As for how inheritance works when the member function is not in the vtable, that depends on what kind of member function it is. All C++ functions are given a mangled name that is stuffed into C’s infrastructure for linking symbols. For static member functions, inheritance is irrelevant since they are tied to the class. Calls to static member functions go directly to the mangled function with no indirections, just as if it had been a global function. For non-static virtual member functions, you use the vtable pointer to find it. For non-virtual member functions, the call goes straight to the function as if a global function had been called (and the this pointer is still passed, even if the function does not use it), since the compiler knows the type and thus can tell the linker to have calls there go to the function through the appropriately mangled name. It is just like calling a global function.

Re: Object-oriented design patterns in C and kernel development

#184
post #113

Earlier quoted context omitted.

In hindsight, I had your remark confused with another remark insisting that struct inode_operations is a vtable, despite it having what would be static member functions in C++, which are never in vtables, and there being no inheritance hierarchy. If you are disciplined enough to do what you said, then I could see that as being OOP, but the context here is of something that is not OOP and only happens to overlap with…

I'm also thinking that these kind of vtables in the linux kernel are what would be implemented by the compiler in C++. But because its self-written, you can be much more creative and do other things, that weren't possible if this would be created by a compiler. Of course you could implement the same in C++ and then it can't be the same as the vtable introduced by the compiler, so you would just end up with to vtables…

If the kernel were written in C++, it would still be done the way it is done now. C++ does not allow unimplemented member functions and the ADTs currently used do. You can emulate that with multiple inheritance, but it is an inferior way of doing this.

As I said, these are NOT vtables. The fact that you and some others keep thinking of them as vtables misleads you into thinking that this can be done using the object oriented tools of C++. It cannot without major hacks and the result would be slower, harder to read and only something that a bureaucrat could like.

Re: Object-oriented design patterns in C and kernel development

#185
post #114

Earlier quoted context omitted.

The article mentions file_operations, but ignores that it has what would be a static member function in C++ in the form of ->check_flags(), which is never in a vtable. The article author is describing overlap between object oriented programming and something else, called data abstraction, which is what is really being done inside Linux, and calling it OOP. You can implement OOP in C if you do vtables for inheritance…

I honestly don't think how a C++ compiler chooses to implement an object method does matter here. It's a function belonging to an object, to which is dynamically dispatched with something I would call a vtable. To me that sounds like a classic example of OOP. Data abstraction is a core of OOP. This pattern can be used to implement inheritance, when it isn't here that doesn't mean its not OOP.

Data abstraction is a separate invention from OOP since it involves abstract data types. What is being used here is an abstract data type. It is not the pattern used in OOP languages and it is not OOP. It bears similarities and overlap with the vtables used to implement some OOP languages. It is like how thumbs bear similarities and overlap with index fingers, but the two are not the same.

Re: Object-oriented design patterns in C and kernel development

#186
post #110

Earlier quoted context omitted.

I would call returning something being implemented as a stub rather than being unimplemented. When something is unimplemented and you try to call it, you crash due to a NULL/invalid pointer dereference, not get an error back. Of course, as far as getting things done is concerned, the two might as well be the same, but as far as how the language works, the two are different.

Having a stub or having a NULL pointer are two ways to leave something unimplemented. Which you use is an implementation detail. You can also use some other sigil instead of NULL.

A stub is an empty implementation. An empty implementation is different from no implementation, where there is no code to execute. It is the difference between writing 0 and writing nothing.

Re: Object-oriented design patterns in C and kernel development

#187

If this is the pattern you prefer, why not choose a language that caters to it? Choosing C just seems like you're TRYING to shoot yourself. I don't care how good you are at coding, this is just a bad decision.

Because they like how C caters to this. This question was asked here several times, please read the answers there.

Ok so... why choose C if they know they're shooting themselves?

Re: Object-oriented design patterns in C and kernel development

#188
post #178

Earlier quoted context omitted.

It can still depend on the type, the answer just doesn't need information from the instance. What speed limits can this road possibly have is a question I want to ask about this specific road. Yet this can be answered by referring to the country, which is already known when you create the road. But the user that asks this question can still ask this about roads in different countries, so this question still is valid.…

Let’s say I have ClassA::Foobar() and ClassB::Foobar(), and ClassB inherits from ClassA. Now let’s say I want to use ClassA::Foobar(), and I access it from the object because this pointer is in the vtable and the object is of type ClassB. Now ClassB::Foobar() executed, which is wrong. This is why static functions are not put into vtables. What Linux is doing is not a vtable, even if it shares similarities. Perhaps yo…

That's a very good example.

When I invoke object->Foobar() I want to invoke the appropriate method for this object, from whatever class that might be. This is exactly what's happening in the kernel here.

When I actually intend to call the method from ClassA, I would either call something like object->base->Foobar() or ClassA->Foobar(object). Note how this is the very example that you are replying to: https://news.ycombinator.com/user?id=1718627440

Re: Object-oriented design patterns in C and kernel development

#189
post #182

Earlier quoted context omitted.

Which means that it's not the language doing OOP, but the programmer.

The definition you quoted requires the language to be the one doing it for it to be a vtable. If the programmer is doing it, then it is not a vtable by that definition.

Ok, we can name it a vtable if it's done by the language and a wtable if it is done by the programmer. I don't care about this distinction, the mechanism is the same, the effects are the same, the implemented theory (OOP) is the same. Heck event the emitted code is the same. I guess the vtable implementations in a C++ compiler are now called wtables.

Re: Object-oriented design patterns in C and kernel development

#190
post #177

Earlier quoted context omitted.

> Static member functions are tied to the class while virtual member functions are tied to the object. That's nice, but the entire point is, that the caller doesn't know the type of the object, it only has a supertype. That's why you need dynamic dispatch here. Of course you can implement dynamic dispatch without function pointers, but it is done with function pointers here. If you don't want to name dynamic dispatch…

The vtable pointer corresponds to the actual type in languages that use vtables to implement inheritance, so you do know the type. Read my previous comment for the bug that would happen if what us being used in Linux were actually used for dynamic dispatch when implementing inheritance, and it should be clear this is something similar, but different.

No the type of an object isn't known until runtime, so the compiler can't know it. Yes you know the type of the vtable, which means you know the supertype. This is true in all languages that don't use duck-typing. No you don't know the assigned values of entries in the vtable, which means you don't know the type of the object.

> Read my previous comment for the bug

No this is not a bug. The entire point of inheritance or dynamic dispatch IS that you call a function from "a different class" aka the subclass the object is an instance of. This is not a bug, this is the entire point of implementing it with vtables.

Post reply on HN