Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

21–30 of 224 posts

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

#21
post #16

> 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 think the author is talking about this: object->ops->start(object) Where not only is it explicit, but you need to specify the object twice (once to resolve the Vtable, and a second time to pass the object to the stateless C method implementation).

Yes I know. From the caller that might seem to be redundant, my argument was about the callee's side. Also it is not truely redundant, as you can write:

    object1->op->start(object2)
    superclass->op->start(object)

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

#22

Note that this is using interfaces (i.e. vtables, records of function pointers), not full object-orientation. Other OO features, like classes and inheritance, have much more baggage, and are often not worth the associated pain.

Field inheritance is surprisingly natural in C, where a struct can be cast to it's first member.

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

#23

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

> Also explicit this eliminates the problem, that you don't know if the variable is an instance variable or a global/from somewhere else. People typically use some kind of naming convention for their member variables, e.g. mFoo, m_Foo, m_foo, foo_, etc., so that's not an issue. I find `foo_` much more concise than `this->foo`. Also note that you can use explicity this in C++ if you really want to.

In code I write, I can know what variables mean. The feature loses its point, when it's not mandatory. Also being explicit allows you to be more expressive with variable name and ordering.

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

#24
post #16

Earlier quoted context omitted.

I think the author is talking about this: object->ops->start(object) Where not only is it explicit, but you need to specify the object twice (once to resolve the Vtable, and a second time to pass the object to the stateless C method implementation).

Yes I know. From the caller that might seem to be redundant, my argument was about the callee's side. Also it is not truely redundant, as you can write: object1->op->start(object2) superclass->op->start(object)

I think both of these invocations are invalid. Using object1's vtable methods on object2, obviously, but in the latter case: the vtable method should just point at the superclass impl, if not overridden. And if overridden and the child impl needs to call the superclass, it can just do so without dispatching through some vtable.

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

#25

Note that this is using interfaces (i.e. vtables, records of function pointers), not full object-orientation. Other OO features, like classes and inheritance, have much more baggage, and are often not worth the associated pain.

What do you think inheritance is, if not composition of vtables? What do you think classes are, if not a composition of a vtable and scoped variables?

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

#26

Note that this is using interfaces (i.e. vtables, records of function pointers), not full object-orientation. Other OO features, like classes and inheritance, have much more baggage, and are often not worth the associated pain.

What do you think inheritance is, if not composition of vtables? What do you think classes are, if not a composition of a vtable and scoped variables?

Those "scoped variables" are the difference. Mutable state adds a great deal of complexity.

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

#27

Earlier quoted context omitted.

What do you think inheritance is, if not composition of vtables? What do you think classes are, if not a composition of a vtable and scoped variables?

Those "scoped variables" are the difference. Mutable state adds a great deal of complexity.

And the style presented in the article uses vtables with "scoped variables". How do you conclude it's "not full object-orientation"?

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

#28

Note that this is using interfaces (i.e. vtables, records of function pointers), not full object-orientation. Other OO features, like classes and inheritance, have much more baggage, and are often not worth the associated pain.

Field inheritance is surprisingly natural in C, where a struct can be cast to it's first member.

Note that you only need to cast for an upcast. To access the first member, you wouldn't need to cast.

It would be nice though, if syntax like the following would be supported:

    struct A 
    {
        int a;
    };

    struct B 
    {
        int b; 
        struct A a;
    };

    void foo (struct A * a)
    {
        struct B * b;

        &b->a = pa;
    }

    struct B b;

    foo (&b.a);

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

#29
post #24

Earlier quoted context omitted.

Yes I know. From the caller that might seem to be redundant, my argument was about the callee's side. Also it is not truely redundant, as you can write: object1->op->start(object2) superclass->op->start(object)

I think both of these invocations are invalid. Using object1's vtable methods on object2, obviously, but in the latter case: the vtable method should just point at the superclass impl, if not overridden. And if overridden and the child impl needs to call the superclass, it can just do so without dispatching through some vtable.

When you think of vtables as unique or owned by an object, then these example seem weird to you. When you think of them as orthogonal to your types/objects, these examples can be useful.

In the first example, object1 and object2 can very much be of the same type or compatible types/subtypes/supertypes. Having vtables per object as opposed to per class to me indicates, that it IS intended to modify the behaviour of an object by changing it's vtable. Using the behaviour of another object of the same type to treat the second object, seams valid to me.

In the second case, it's not about the child implementation dispatching to the superclass, it's about some external code wanting to treat it as an object of the supertype. It's what in other languages needs an upcast. And the supertype might also have dynamic behaviour, otherwise you of course wouldn't use a vtable.

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

#30

Earlier quoted context omitted.

Field inheritance is surprisingly natural in C, where a struct can be cast to it's first member.

Note that you only need to cast for an upcast. To access the first member, you wouldn't need to cast. It would be nice though, if syntax like the following would be supported: struct A { int a; }; struct B { int b; struct A a; }; void foo (struct A * a) { struct B * b; &b->a = pa; } struct B b; foo (&b.a);

Yeah you're right, I meant the other way around. Also another loosely related idea is the container_of macro in Linux kernel.
Post reply on HN