Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

101–110 of 224 posts

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

#101
post #47
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).

Nothing a little macro magic couldn't fix.. #define CALL(object, function, ...) (object->ops->function(object, __VA_ARGS__))

You can also just replicate the vtable of sorts in C that keeps track of things when new objects are created.

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

#102

Earlier quoted context omitted.

this in C++ is just a regular pointer, it has no special footguns, just the typical ones you have with pointers in general

that's not really true - unlike a regular pointer, `this` is not allowed to be null, thus removing `if(this == nullptr)` is always a valid optimization to do.

[deleted]

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

#103

Earlier quoted context omitted.

that's not really true - unlike a regular pointer, `this` is not allowed to be null, thus removing `if(this == nullptr)` is always a valid optimization to do.

It absolutely is allowed to be null: #include struct Foo { void bar() { std::cout bar(); } will print 0

    Foo *p = nullptr;
    p->bar();
That's undefined behavior. It's "allowed" in the sense of "yes it's possible to write, compile and run that code", but the language makes no guarantees about what the results will be. So maybe not the most useful definition of "allowed".

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

#104
post #47
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).

Nothing a little macro magic couldn't fix.. #define CALL(object, function, ...) (object->ops->function(object, __VA_ARGS__))

You can just use C++ instead of reinventing a worse version of C++98!

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

#105
post #48
post #24

Earlier quoted context omitted.

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.

You are wrong about those invocations being invalid. Such patterns happen in filesystem code fairly often. The best example off the top of my head is: error = old_dir->i_op->rename(rd->new_mnt_idmap, old_dir, old_dentry, new_dir, new_dentry, flags); https://github.com/torvalds/linux/blob/master/fs/namei.c#L51... That is a close match for the first example, with additional arguments. It is helpful to remember that thi…

I don't agree that your example pattern matches to the example I'm complaining about. vfs_rename() is using old_dir's vtable on old_dir. The vtable matches the object.

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

#106
post #87
post #61

Earlier quoted context omitted.

OOP cannot be a formalization of what predated it because the predating patterns support things that OOP explicitly disallows, like instantiation with unimplemented functions. That is extremely useful when you want to implement an optional function, or mutually exclusive functions such that you pick which is optional. This should be the case in the Linux VFS with ->read() and ->read_iter(). Also, ASTs were formalized…

OOP does not disallow instantiation with unimplemented functions, it's just an artefact of implementation in some languages.

OOP only disallows inheritance with unimplemented functions when it's a contract violation.

So that is to say, if the base class has a certain function which must be implemented and must provide certain behaviors, then the derived class must implement that function and provide all those behaviors.

The POSIX functions like read and write do not have a contract which says that all implementations of them must successfully transfer data. Being unimplemented (e.g returning -1 with errno EOPNOTSUPP or whatever) is allowed in the contract.

OOP just wants a derived thing to obey the contract of the abtraction it is inheriting, so if you want certain liberties, you have to push them into the contract.

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

#108
post #6
post #2

> The article describes how the Linux kernel, despite being written in C, embraces object-oriented principles by using function pointers in structures to achieve polymorphism. This technique predates object oriented programming. It is called an abstract data type or data abstraction. A key difference between data abstraction and object oriented programming is that you can leave functions unimplemented in your abstrac…

In Smalltalk and Objective-C, you just check at runtime whether an object instance responds to a message. This is the original OOP way. It's sad that OOP was corrupted by the excessively class-centric C++ and Java design patterns.

Sure, but that is a a horrible coding pattern. Even good smalltalk code doesn't rely on this. It's dogshit and lazy

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

#109
post #105
post #48

Earlier quoted context omitted.

You are wrong about those invocations being invalid. Such patterns happen in filesystem code fairly often. The best example off the top of my head is: error = old_dir->i_op->rename(rd->new_mnt_idmap, old_dir, old_dentry, new_dir, new_dentry, flags); https://github.com/torvalds/linux/blob/master/fs/namei.c#L51... That is a close match for the first example, with additional arguments. It is helpful to remember that thi…

I don't agree that your example pattern matches to the example I'm complaining about. vfs_rename() is using old_dir's vtable on old_dir. The vtable matches the object.

It is not a vtable. It is a structure of function pointers called struct inode_operations. It is reused for all inodes in that filesystem. If you get it from one callback, you can safely use it on another struct inode on the same filesystem without a problem because of that, because nobody uses this like a vtable to implement an inheritance hierarchy. There are even functions in struct inode_operations that don’t even require the inode structure to be passed, such as ->readlink, which is most unlike a vtable since static member functions are never in vtables:

https://www.kernel.org/doc/html/latest/filesystems/vfs.html

As I said previously, it is helpful to remember that this is not object oriented programming and not try to shoehorn this into the paradigm of object oriented programming. Calling this a vtable is wrong.

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

#110
post #87

Earlier quoted context omitted.

OOP does not disallow instantiation with unimplemented functions, it's just an artefact of implementation in some languages.

OOP only disallows inheritance with unimplemented functions when it's a contract violation. So that is to say, if the base class has a certain function which must be implemented and must provide certain behaviors, then the derived class must implement that function and provide all those behaviors. The POSIX functions like read and write do not have a contract which says that all implementations of them must successfu…

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.
Post reply on HN