Live data from Hacker News

Object-oriented design patterns in C and kernel development

oshub.org

141–150 of 224 posts

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

#141

Earlier quoted context omitted.

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);

In what scenario would this be useful? If foo() takes a struct A, it should be more generic and have no knowledge about the more specialized struct B.

In exact that same scenario, that you would cast to a subclass in another language, it's about language support for what for example the kernel does with container_of.

Of course casting to a subclass isn't guaranteed to succeed always, but for example when you have actually declared it as the subclass elsewhere it's fine without checking for isinstance.

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

#142
post #130
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).

What guarantee do you have that ->ops is a vtable? It could contain function pointers that don’t take an implicit this argument like struct file_operations in Linux does. It could also contain variables that are non-pointers. Neither is allowed in a vtable, but both are fine to do in C.

As it isn't the compiler that creates the vtable, you can also have the equivalent of this as the last parameter or where you want it to be.

> It could also contain variables that are non-pointers.

The convention of it being a pure vtable is that it just doesn't.

> Neither is allowed in a vtable

Who is the vtable membership authority? :-)

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

#143
post #125

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.

vtables contain function pointers to functions that take “this” pointers. The author mentions struct file_operations as an example of a vtable. struct file_operations contains a pointer to a function that does not take “this” pointer. It is not even a vtable.

I would still call it a vtable. Who assures you that every function of a class needs a pointer to the object instance? When you don't need it, you can just leave it of when you roll your own.

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

#144

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…

That sounds like a case of the Liskov substitution principle.

Yes it is, but the point is that without the contract being defined, we can't apply the principle; the details of the interface contract determine what it means to be substitutable.

The LSP is never absolute in a practical system. Because why would you have, say, in a casee of inheritance, a Y which is an new kind of X, if all it did was substitute for X, and behave exactly the same way? Just use X and don't create Y; why create a substitute that is perfectly identical.

If there is a reason to introduce a new type Y which can be used where X is currently used, then it means they are not substitutable. The new situations need a Y and not X, and some situations don't need a Y and stay with X.

In a graphics program, an ellipse and rectangle are substitutable in that they have a draw() method and others, so that they plug into the framework.

But they are not substitutable in the user's design; where the user needs an ellipse, a rectangle won't do, and vice versa.

In that case the contract only cares about the mechanics of the program: making multiple shapes available in a uniform way, with a program organization that makes it easy to code a new shape.

The substitution principle serves the program organization, and not much more.

So with the above discussion in place, we can make an analogy: an ellipse object in a vector graphics program can easily be regarded as a version of a rectangle with unimplemented corners.

The user not onnly doesn't mind that the corners are not implemented, but doesn't want them because they wouldn't make sense.

In the same way, it doesn't make sense to have lseek() on a pipe, or accept() on TTY descriptor or write() on a file which is read only to the caller, etc.

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

#145
post #120

Earlier quoted context omitted.

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

> 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 method is not in the vtable?

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

#146
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 Objective-C being based on C, means it would never be safe while remaining compatible with C.

Also dynamic runtime dispatch Smalltalk style can never be as fast as the VMT based dispatch, or compile time dispatch via generics, even with all the optimizations in place, that objc_msgSend() has had during its lifetime.

Still, Metal is implemented in Objective-C, so there is that.

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

#147
post #133

Earlier quoted context omitted.

The curiosity of learning is infeasible given that there are >15,000 programming languages. You might say to only learn the major/influential languages, but I have found my curiosity to wane with every additional language that I learn. So far, I have either used or dabbled in C, C++, FORTRAN, SML/NJ, PHP, Java, JavaScript, Python, Go, POSIX Shell, Assembly and SQL stored procedures. That is not to mention different d…

How do you got proficient in so many languages? I think it takes some years, before you start to think in a language.

I did not know they say the same thing about programming languages.

Based on his comment, I did not think that he is proficient in them, but that he has used them, which is fair enough, so have I, sans all the ones tied to either Apple (Swift) or Microsoft (C#).

I have some projects in Haskell just for curiosity's sake, and because what I wanted seemed like it would be nice in Haskell, and it indeed looks quite elegant to me, for this one particular project. Haskell is not a language I would use generally. OCaml is.

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

#148

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

Mandatory this can also be a major hit in readability. What if you have a class that implements the abc-formula. You get

  (- this->b + sqrt(this->b * this->b - 4 this->a * this->c))/(2 * this->a)
and

  (- this->b - sqrt(this->b * this->b - 4 this->a * this->c))/(2 * this->a)
This is a readability problem for any class that is used to do computations.

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

#149
post #124
post #13

Earlier quoted context omitted.

Actually, no. "AN ALGORITHMIC THEORY OF LANGUAGE", 1962 https://apps.dtic.mil/sti/tr/pdf/AD0296998.pdf In this paper they are known as plexes, eventually ML and CLU will show similar approaches as well. Only much latter would Lisps evolve from plain lists and cons cells.

You caused me to do some digging. That publication is dated November 1962. The Lisp 1.5 manual’s preface is dated August 17, 1962, which is even older. It describes lambdas and property lists, which seem like they can be used to implement ADTs, although I do not have a Lisp 1.5 interpreter since those are obsolete, so I cannot verify that. Computer history articles claim that Simula, the first object oriented languag…

Plexes are first mentioned in 1960

https://dl.acm.org/doi/pdf/10.1145/366199.366256

and the paper even starts with a critique of the efficiency of Lisp's approach for representing data with cons pairs (citing McCarthy's paper from the same year).

You might also want to watch Casey's great talk on the history of OOP

https://www.youtube.com/watch?v=wo84LFzx5nI

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

#150

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

You must be joking.

That would be a complete redability disaster... at least for C++. Java peeps probably won't even flinch ;)

Post reply on HN