Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

71–80 of 224 posts

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

#71

Earlier quoted context omitted.

The interesting thing is, that in the OOP implementation inheritance IS composition of vtables and data. It's really only syntactic sugar, that is sometimes not unambiguous.

This is not quite correct. OOP implementation inheritance involves a kind of "open recursion" (that is, calls to base-class methods can end up dispatching to implementations from a derived class) that is not replicated with pure composition. All method calls, including method calls that originate from code in some class anywhere in the hierarchy, ultimately dispatch through the vtable of whatever object they're calle…

But that's exactly the same you would need to implement manually when you use composition. When constructing, you also need to construct the contained objects, when doing something that should affect a contained object, you need to dispatch it.

When a method is never overridden, it doesn't need to be in the vtable.

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

#72
post #65

Earlier quoted context omitted.

> My point is that this pattern is not object oriented programming. Isn't this exactly how most (every?) OOP language implements it? You would say a C++ virtual method isn't OOP?

Member function pointers and member functions in C++ are two different things. Member function pointers are not OOP. They are data abstraction. The entire point of OOP is to make contracts with the compiler that forcibly tie certain things together that are not tied together with data abstraction. Member functions are subject to inheritance and polymorphism. Member function pointers are not. Changing the type of your…

Yeah, but the compiler implements these by adding vtables, propagating vtables values across inheritance hierarchies, adding another parameter.

You claim when the compiler does this, it's OOP, but when I do it, it's not?

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

#73
post #68

Earlier quoted context omitted.

> My point is that this pattern is not object oriented programming. I think the "is/is not" question is not so clear. If you think of "is" as a whether there's a homomorphism, then it makes sense to say that it is OOP, but it can qualify as being something else too, ie. it's not an exclusionary relationaship.

Object oriented programming implies certain contracts that the compiler enforces that are not enforced with data abstraction. Given that object oriented programming and data abstraction two live side by side in C++, we can spot the differences between member functions that have contracts enforced, and members function pointers that do not. Member functions have an implicit this pointer, and in a derived class, can ca…

So you can opt out or in to syntactic sugar, that makes C++ an interesting and useful language, but how you implement OOP, doesn't really affect if it is OOP.

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

#74

> Having to pass the object explicitly every time feels clunky, especially compared to C++ where this is implicit. I personally don't like implicit this. You are very much passing a this instance around, as opposed to a class method. Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else.

Agreed, one of the biggest design mistakes in the OOP syntax of C++ (and Java, for that matter) was not making `this` mandatory when referring to instance members.

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

#75

Earlier quoted context omitted.

This is not quite correct. OOP implementation inheritance involves a kind of "open recursion" (that is, calls to base-class methods can end up dispatching to implementations from a derived class) that is not replicated with pure composition. All method calls, including method calls that originate from code in some class anywhere in the hierarchy, ultimately dispatch through the vtable of whatever object they're calle…

But that's exactly the same you would need to implement manually when you use composition. When constructing, you also need to construct the contained objects, when doing something that should affect a contained object, you need to dispatch it. When a method is never overridden, it doesn't need to be in the vtable.

That's not what people usually mean by "composition" though. The whole point of "use composition over inheritance" is to avoid that behavior.

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

#76

> Having to pass the object explicitly every time feels clunky, especially compared to C++ where this is implicit. I personally don't like implicit this. You are very much passing a this instance around, as opposed to a class method. Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else.

The implicit this sounds to me like magic. Magic!

Ask how do I do this, well see it's magic. It just happens.

Something went wrong? That's also magic.

After 40 years I hate magic.

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

#77

> Having to pass the object explicitly every time feels clunky, especially compared to C++ where this is implicit. I personally don't like implicit this. You are very much passing a this instance around, as opposed to a class method. Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else.

I don't quite agree, especially because the implicit this not only saves you from explicitly typing it, but also because by having actual methods you don't need to add the struct suffix to every function.

    mystruct_dosmth(s);
    mystruct_dosmthelse(s);
vs

    s->dosmth();
    s->dosmthelse();

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

#78

Earlier quoted context omitted.

But that's exactly the same you would need to implement manually when you use composition. When constructing, you also need to construct the contained objects, when doing something that should affect a contained object, you need to dispatch it. When a method is never overridden, it doesn't need to be in the vtable.

That's not what people usually mean by "composition" though. The whole point of "use composition over inheritance" is to avoid that behavior.

I don't see how you can use composition without eventually calling methods of the contained objects. Every method of the outer object either uses an inner object or it doesn't. Yes, using the inner object doesn't always means just delegating to a single call. You maybe would implement the outer by calling an inner objects method multiple times or different methods, but nothing stops you of doing the same thing with a super class. When you don't call to an inner object, it's the same as you adding another method to the subclass, without it being present in the parent class.

I think composition over inheritance is only about being explicit. That's it.

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

#79
post #77

> Having to pass the object explicitly every time feels clunky, especially compared to C++ where this is implicit. I personally don't like implicit this. You are very much passing a this instance around, as opposed to a class method. Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else.

I don't quite agree, especially because the implicit this not only saves you from explicitly typing it, but also because by having actual methods you don't need to add the struct suffix to every function. mystruct_dosmth(s); mystruct_dosmthelse(s); vs s->dosmth(); s->dosmthelse();

My problem with implicit this is more, that you can access member variables, without it being explicit, i.e. about the callee, not about the caller.

For the function naming, nothing stops you from doing the same in C:

   static dosmth (struct * s);
   
   s->dosmth = dosmth;
That doesn't stop you from mentioning s twice. While it is redundant in the common case, it isn't in every case like I wrote elsewhere. Also this is easily fixable as written several times here, by a macro, or by using the type directly.

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

#80

> Having to pass the object explicitly every time feels clunky, especially compared to C++ where this is implicit. I personally don't like implicit this. You are very much passing a this instance around, as opposed to a class method. Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else.

Agreed, one of the biggest design mistakes in the OOP syntax of C++ (and Java, for that matter) was not making `this` mandatory when referring to instance members.

C++ and Java went for the "objects as static closures" route, where it doesn't make any sense to have a `this`. Or, they made them superficially look like static closures, which in hindsight was probably not the best idea. Anyway, Java lets you use explicit `this`, I don't recall whether C++ makes it into a footgun or not.
Post reply on HN