Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

111–120 of 224 posts

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

#111
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…

> like instantiation with unimplemented functions I think this is more of an effect of C distinguishing between allocating memory (aka object creation) and initialization, which other languages disallow for other reasons, not because there are not OOPy enough.

Unlike OOLs, C does not enforce contracts around structures (objects). You are free to do literally anything you want to them.

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

#112

Earlier quoted context omitted.

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?

Ìf you do it, it can still be OOP, its just not in an OO language. People have trouble separating using a paradigm and using a language focused on the paradigm, for some reason.

[deleted]

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

#113
post #83

Earlier quoted context omitted.

The entire point of OOP in every OOP language that I have ever used has been to have the language try to constrain what you can do by pushing restrictions on syntactic sugar involving objects, inheritance and encapsulation, so I would say yes. The marketing claims that people will be more productive at programming by using these.

Yes, you need to have that to have an OOP language. OOP is object-oriented _Programming_, it's about how you program, not what features the language has.

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

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

#114
post #81

Earlier quoted context omitted.

By this logic, C is an objective oriented language. It is widely held to not be. That is why there were two separate approaches to extend it to make it object oriented, C++ and Objective-C.

You can implement OOP in C as you can in any language, the article is an example of this. C is not an OOP language in any way, it doesn't have any syntactic features for it and use the term "object" for something different.

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 hierarchies manually, among other things, but that is different than what Linux does.

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

#115
post #110

Earlier quoted context omitted.

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.

Crashing is optional, depending on error model of the language. C has pitiful error model, thus you'll usually end up jumping to 0... but I recall at least one C environment where that gave you an error back instead of crash.

As far as OOP is concerned, lack of implementation is not an issue in instantiating something - an object will just not understand the message, possibly catastrophically.

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

#116
post #34

A few years ago Peterpaul developed a lightweight object-oriented system on top of C that was really pleasant to use[0]. No need to pass in the object explicitly, etc. Doesn't have the greatest documentation, but has a full test suite (e.g., [1][2]). [0] https://github.com/peterpaul/co2 [1] https://github.com/peterpaul/co2/blob/master/carbon/test/pas... [2] https://github.com/peterpaul/co2/blob/master/carbon/test/pas…

I feel like Vala tries to fit in this niche too.

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

#117
post #10

Earlier quoted context omitted.

Yes, that is how microservices were implemented in the days of NeXTSTEP. with PDO. https://en.wikipedia.org/wiki/Portable_Distributed_Objects

So why did Swift become a thing? Or does Swift has this too?

Because Swift adds many other features.

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

#118
post #10

Earlier quoted context omitted.

Yes, that is how microservices were implemented in the days of NeXTSTEP. with PDO. https://en.wikipedia.org/wiki/Portable_Distributed_Objects

So why did Swift become a thing? Or does Swift has this too?

Swift isn't messaging-based, it's protocol-based. (Except it's also messaging-based if you use @objc.)

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

#119
post #10

Earlier quoted context omitted.

Wait, so in obj-c, could you also write some kijdnof doesnotunderstand method to achieve some dynamic method dispatch?

Yes, that is how microservices were implemented in the days of NeXTSTEP. with PDO. https://en.wikipedia.org/wiki/Portable_Distributed_Objects

It's how many things are implemented, like UI message routing, IPC, undo, test mocks.

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

#120
post #68

Earlier quoted context omitted.

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…

> Object oriented programming implies certain contracts that the compiler enforces Sorry, but where did you got this definition from? I've always thought OOP as a way of organizing your data and your code, sometimes supported by language-specific constructs, but not necessarily. Can you organize your data into lists, trees, and hashmaps even if your language does not have those as native types? So you can think in a…

> 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 function in C++. That is never in a vtable.

If Al Viro were trying to restrict himself to object oriented programming, he would need to remove function pointers to what are effectively the equivalent of static member functions in C++ to turn it into a proper vtable, and handle accesses to that function through the “class”, rather than the “object”.

Of course, since he is not doing object oriented programming, placing pointers to what would be virtual member functions and static member functions into the same structure is fine. There will never be a use case where you want to inherit from a filesystem implementation’s struct file_operations, so there is no need for the decoupling that object oriented programming forces.

> I've always thought OOP as a way of organizing your data and your code, sometimes supported by language-specific constructs, but not necessarily.

It certainly can be, but it is not the only way.

> Can you organize your data into lists, trees, and hashmaps even if your language does not have those as native types?

This is an odd question. First, exactly what is a native type? If you mean primitive types, then yes. Even C++ does that. If you mean standard library compound types, again, yes. The C++ STL started as a third party library at SGI before becoming part of the C++ standard. If you mean types that you can define, then probably not without a bunch of pain, as then we are going back to the dark days of manually remembering offsets as people had to do in assembly language, although it is technically possible to do in both C and C++.

What you are asking seems to be exactly what data abstraction is, which involves making an interface that separates use and implementation, allowing different data structures to be used to organize data using the same interface. As per Wikipedia:

> For example, one could define an abstract data type called lookup table which uniquely associates keys with values, and in which values may be retrieved by specifying their corresponding keys. Such a lookup table may be implemented in various ways: as a hash table, a binary search tree, or even a simple linear list of (key:value) pairs. As far as client code is concerned, the abstract properties of the type are the same in each case.

https://en.wikipedia.org/wiki/Abstraction_(computer_science)...

Getting back to doing data structures without object oriented programming, this is often done in C using a structure definition and the CPP (C PreProcessor) via intrusive data structures. Those break encapsulation, but are great for performance since they can coalesce memory allocations and reduce pointer indirections for objects indexed by multiple structures. They also are extremely beneficial for debugging, since you can see all data structures indexing the object. Here are some of the more common examples:

https://github.com/openbsd/src/blob/master/sys/sys/queue.h

https://github.com/openbsd/src/blob/master/sys/sys/tree.h

sys/queue.h is actually part of the POSIX standard, while sys/tree.h never achieved standardization. You will find a number of libraries that implement trees like libuutil on Solaris/Illumos, glib on GNU, sys/tree.h on BSD, and others. The implementations are portable to other platforms, so you can pick the one you want and use it.

As for “hash maps” or hash tables, those tend to be more purpose built in practice to fit the data from what I have seen. However, generic implementations exist:

https://stackoverflow.com/questions/6118539/why-are-there-no...

That said, anyone using hash tables at scale should pay very close attention to how their hash function distributes keys to ensure it is as close to uniformly random as possible, or you are going to have a bad time. Most other applications would be fine using binary search trees. It probably is not a good idea to use hash tables with user controlled keys from a security perspective, since then a guy named Bob can pick keys that cause collisions to slow everything down in a DoS attack. An upgrade from binary search trees that does not risk issues from hash function collisions would be B-trees.

By the way, B-trees are containers and cannot function as intrusive data structures, so you give up some convenience when debugging if you use B-Trees.

Post reply on HN