Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

191–200 of 224 posts

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

#191
post #181

Earlier quoted context omitted.

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 fo…

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

Yes, but you also need to specify the type in C. ((void *)p)->foo only works in New B not in C.

> IMO these are a mistake

Forgetting to check bounds does always result in these problems in C, this is not specific to VLAs. I find them useful.

> Exceptions are problematic in their implementation

Ok, but that means to me having these in the language is only a downside.

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

#192
post #183

Earlier quoted context omitted.

> 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 questionab…

> The calling convention for C++ non-static member functions always includes a this pointer, even if the function does not use it.

Yes. Since we are not in C++ we can choose to get rid of this useless pointer.

> 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.

That problem has nothing to do with the this pointer specifically. When you change the method signature of an inherited method you always have this problem. This simply means, that the superclass prescribes limits to subclasses, which is why it's possible to use a subclass inplace of a superclass.

> Maybe in very special cases whole program optimization could safely remove the this pointer, but it is questionable whether any compiler author

Yes, that's why its not done in C++, but we can do it, if we handroll it.

> it would break ABI stability

It does not if it has always been like this.

> 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

In other words, ->check_flags() can't be implemented as a static member functions in C++. It would simply have a this pointer, that it just wouldn't use, since C++ has no way to express non-static member functions, that just don't take a this pointer.

> thus can tell the linker to have calls there go to the function

In our case the linker can only resolve the call to the appropriate vtable, since the type isn't known until runtime.

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

#193
post #182

Earlier quoted context omitted.

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.

It is not the same theory, since it is an ADT, not anything object oriented. Different theories can and do overlap. The emitted code is also not the same, since there is no implicit this pointer. You are the one who posted a definition you found and then claimed that it agreed with you, when it did not and now are reneging on your use of it. You do not understand this topic as well as you think you do and this is a silly hill to die on.

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

#194
post #177

Earlier quoted context omitted.

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 inheritanc…

I never said that the type was known before runtime in OO. Your not a bug comment sounds awfully like an all bugs are features. Implementing static member functions this way would cause undefined behavior, which is a bug.

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

#195
post #178

Earlier quoted context omitted.

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.yco…

You don’t implement calls to static member functions by putting them into a vtable, which is one of many reasons why this is not a vtable. The proper way to implement static functions is through static dispatch.

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

#196
post #184

Earlier quoted context omitted.

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…

If the kernel were written in C++, it simply had the incentive to be less creative. Since it isn't it can be. It's just a restriction imposed by C++, not a restriction in the loosely defined paradigm of OOP.

> As I said, these are NOT vtables

Ok, you just define vtables differently then me. To me a vtable is a table of virtual functions that are used to implement polymorphic behaviour of objects. This applies to their usage in the kernel and the article. Feel free to introduce a new term for this. If your only distinction is whether these are created by a compiler, this is just a distinction I don't care about.

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

#197

Earlier quoted context omitted.

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?

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

> Because they like how C caters to this.

We(aka I) think we are shooting ourselves less, because C represents the algorithms more in a way how we want to express them. C's lack of syntactic sugar means dynamic dispatch is always visible. C not prescribing which function pointers you can use, means that the most fitting way can be chosen as described by the article and the LWN post, as opposed to shoehorning it into some paradigm prescribed by the language, which causes more problems done the line.

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

#198
post #183

Earlier quoted context omitted.

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 questionab…

> The calling convention for C++ non-static member functions always includes a this pointer, even if the function does not use it. Yes. Since we are not in C++ we can choose to get rid of this useless pointer. > 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. That problem has nothing to do…

> Yes. Since we are not in C++ we can choose to get rid of this useless pointer.

If you were trying to implement OOP in the kernel in C and implemented a vtable, you cannot get rid of the this pointer in vtable entries since a child class might want to use it in the overrode definition. It is one of the same reasons why you cannot remove it in C++. The entire point of a vtable is to enable inheritance. If OOP really were being done, an out of tree module could make a class that inherits from this one without needing any code changes and use the this pointer, but you cannot do that if you drop the this pointer. I already explained this.

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

#199
post #186

Earlier quoted context omitted.

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.

If you care about this distinction, yes. However the LWN post describes how both can be used to implement the same behaviour, that their is no defined special implementation.

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

#200
post #185

Earlier quoted context omitted.

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.

To cite Wikipedia:

> Object-oriented programming (OOP) is a programming paradigm based on the object – a software entity that encapsulates data and function(s). An OOP computer program consists of objects that interact with one another. A programming language that provides OOP features is classified as an OOP language [...]

You don't disagree, that this kernel pattern is about data abstraction. You probably don't disagree, that the kernel uses functions. The kernel uses "objects" (FS implementations) that follow a defined set of functions, sometimes called "class" (vtables/wtables/however you like to call them). Therefore I conclude what the kernel does here is a prime example of OOP.

Post reply on HN