The Big OOPs: Anatomy of a Thirty-five-year Mistake – BSC 2025

For those unfamiliar with the Expression Problem, some context. Not everyone is a language nerd, though I’ll concede the percentage on this forum is probably higher than normal. :wink:

One of the things I really like about Zig’s design is that it doesn’t overly commit to a default direction of abstraction. It gives you good enough tools that you can pull the language in either direction if you need to, but somewhere on the order of 95% of the time, the tools you already have are good enough.

Programming in Zig reminds me a lot of programming in Lua, in that way.

(I consider this high praise.)

That is by tradition motivated and not at all obvious conclusion though, isn’t is? Some people could even say it’s flat out wrong, but I don’t have enough experience with GUI development to claim that’s the case.

Maybe, there are immediate mode GUIs that don’t use that approach.

Regardless, you can disagree with Mitchell on this specific example, but arguing that OOP is categorically always bad requires a lot of work to substantiate the claim.

As another example, I personally believe that, in the context of enterprise software development, DDD (domain driven design) and its connection to OOP, is a reasonable way to make progress in that context. And more in general having a “compile time hierarchy of encapsulation that matches the domain model” (the exact thing casey thinks is categorically wrong) is in my opinion literally the only good thing about microservices (i.e. splitting your services in a way that mirrors boundaries within the company).

4 Likes

That is of course correct. I agree that saying OOP is always bad requires a lot of substantiation (and therefore disagree with Casey making these broad points), same as saying that it’s the best for GUIs.

I sometimes maybe get too focused on the specifics and ignore the whole idea, sorry about that.

OOP brought us here:
private implicit explicit static abstract virtual protected public readonly required override class interface object record strict private strict protected published

I like
struct

3 Likes

As an aside based on your point, Zig implemented member visibility perfectly: a single keyword to make declarations public, and private members being scoped to the file, not the type or even worse, the “package” scope in Go.

Honestly, even the fact that all struct fields are public has influenced the way that I design my types for the better, as it makes me question “do I really need this field polluting the struct, or can I find a better way”. By trying to avoid the existence of “private fields” and having to document that they should not be used, which never feels good, made me realize there are usually alternative and often better solutions that can be found. It just naturally guides you into better composition.

1 Like

I associate this syntax rather with functional programming than OOP :wink: Because it’s this uniform function call syntax which allows chaining instead of nesting, e.g.:

const res = a.map().filter().sort();

…the nested alternative would be inside-out and requires a lot more mental gynmastics:

const res = sort(filter(map(a)));

…in the end it’s just a syntax-sugar detail - but this time actually important syntax sugar.

Zig implemented member visibility perfectly

I wouldn’t call it ‘perfect’, for instance I’d like to express that a public item is readonly from outside a module, but read/write inside the module to avoid wrapping the item in a ‘getter function’.

In general I would like languages to experiment more with a filesystem-like access model for data. E.g. what if all data is organized in a filesystem-like tree (we already have that tree-like structure for code with modules and functions), and some part of the source code is responsible for defining an access-rights-map of code-tree-nodes to data-tree-nodes.

E.g. instead of ‘public vs private’ a ‘readonly vs read/write’ model (which is very different from const vs var, since ‘readonly’ is just a different view of some code locations on runtime data) - and there’s not much wrong with all data being visible to everyone as long as its not writable by everyone (although general visibility could also be part of the ‘access rights model’).

2 Likes

In C++, IIRC, the const keyword on a method meant a guarantee that the method does not modify the attributes of this, that is: it’s a read-only method.
That’s something I liked a lot.
In PL/SQL, there are IN, OUT and IN OUT
parameters, which mean read-only, write-only and read/write. And somewhat related, there was PRAGMA RESTRICT_REFERENCES specifying the purity wrt the session 's and DB’s state, for deciding if and where a function can be used inside SQL. The compiler checked this, but one could specify TRUST to override this.
This is a feature I missed in C++.
Eg in some cases, you want to just cache or hash something, but storing the result violates the const keyword, even though the method is read-only from a higher level point of view.

I think that the r/w analogy has proven to be useful, but this is independent of OOP.
In fact, PL/SQL also allows OOP, but in this regard (specifying r/w access for objects and methods), it either fails or I don’t quite understand it.

Fun fact: I have been working as an Oracle developer (not for Oracle) for more than 30 years now and I have felt the need for OOP in PL/SQL exactly once, for a single class for a logging framework.

While I like OOP, the past has shown that reasonable code can also be written without it.

The sad truth is that those who started programming after ~1993 have been indoctrinated with OOP, or worse, that OOP=Java, and cannot even think that other ways of professional coding are possible at all.

Of course, people who use Zig are an exception to this rule.

2 Likes

Maybe it is good, maybe not. I do not know. Sometimes I feel the need for privates or readonly, but that seems to mainly come from old memories.
The main thing I am aware of using Zig for a few months is the ultimate feeling of programming freedom. Nowhere a restriction. Nowhere a hidden thing.
I worked a lot with oop and often struggling: “where is the goddamn implementation in this virtual method chain or interface”.

2 Likes

I don’t see this.

Inheritance means a single pointer per runtime object that you can chase through a fairly long chain to find the appropriate function call (and people bitched about what a waste of memory it was!). Composition (or anything else) means multiple pointers per runtime object.

C++ dates to 1985! Saving bytes per object was a big deal. Segment:offset was considered a good engineering tradeoff. Stuffing data in the upper couple of bytes in pointers (look at all those wasted bits!) was a clever hack. etc.

Of course, the problem now is that those optimizations are useless. Even worse, things like pointer chasing are anti-performance

Note that I am talking about stuff allocated on the heap at runtime. Those runtime objects mostly defined the memory usage of your program back then.

1 Like

I guess AI meant something a whole lot different to you then. :wink:

4 Likes

This is really only needed because the this-parameter is implicit in C++, e.g. a method void Bla::bla() const would otherwise be written void Bla::bla(const Bla* this) - which would result in the same behaviour.

(my point was though that I want to control readwrite vs read/only access without having to access the data through setter/getter functions)

1 Like

Nah, if you nest the ‘composites’ it’s the same resulting (output) code, you just have to type a bit more, e.g.:

// with inheritance
int a = obj->memberInBase;
// with composition
int a = obj->base.memberInBase;

Both will result in a single memory access (e.g. no extra pointer indirection).

(btw, this is also why I like that C has -> vs ., you see exactly how many pointer-indirections are needed in an ‘access chain’ like this, the . is always free)

4 Likes

Yeah this is mostly fine, but looking at some parts of the Zig stdlib / build system, there seem to be quite a few places sprinkled with struct members which are clearly ‘internal implementation details’ and which are not meant to be accessed directly but only through some sort of wrapper function.

That would be OK I think, but it’s not always clear what is the purpose of the field. That’s the main problem I would say.

I find that point view kind of shallow.

It’s ultimately irrelevant whether Alan Kay designed OOP for big teams or for something else.

That’s only true if:

  1. You only care about how effective OOP is as a technique
  2. You assume we have all the necessary data to judge how effective OOP is as a technique

Point 1. is abolutely subjective, each person has its own interests. In my case, if I found out that a widely used pattern was developed by highly capable people and, at the same time, that pattern is pretty ineffective, the question that would immediately come to mind would be “What’s up with that?” and I think there’s value to that question.

But even if you disagree, I don’t think Point 2. holds true; only from the comments on this thread it’s clear to me that measuring how effective OOP depends a lot on the problem domain, external factors, etc, and it’s pretty hard to draw any general conclusions. In that context, knowing the reasoning behind the creation of the technique can be valuable, even if you only care about it’s effectiveness. To put it another way:

Had Casey actually discovered that this was the case, that OOP was designed entirely for big-scale software created by big teams, should our evaluation of it change then?

Probably? It’s hard to argue based on a hypothetical, but if they were to discover that, e.g., due to the technical constrains of the time, Alan Kay designed OOP for big teams under the assumptions that team members would communicate sparsely and that it would be hard to share code between them, then that would be something to consider when thinking about how and when OOP can be useful, don’t you think?

1 Like

It sounds like you’re defending an appeal to authority. I don’t need some other person to tell me whether OOP is good or not, even if they are a fellow member of the AK gang :smiling_face_with_sunglasses:. I’m perfectly capable of evaluating techniques myself. You should have the same level of self-respect.

Who cares what Alan, Casey, or Andrew says? Think for yourself.

10 Likes

This is a nuanced point. You are correct in stating that, for example, it would be legitimate to just have an interest in the history of computing. That said, if that were the case, Casey’s talk should not be considered good material. He’s not a computer historian, he’s just interested in proving a point about OOP and this is what has driven his selection for what to present and what to omit, and how to interpret each historical artifact that he came across (eg).

I’ll come back to Casey in a moment.

Even though it’s legitimate for people to have different interests, when it comes to community building what you decide to focus on has important consequences in the overall direction that the community will take and consequently the culture and ecosystem surrounding Zig in our specific case.

There is a lot to gain by deliberately valuing perspectives focused on creating high-quality software over all others. The type of discourse you have is what decides the kind of people you attract to your community, and that creates a virtuous cycle, if the perspective selection was done correctly, and a vicious cycle otherwise.

This is why rules like this one are great (taken from the software you can love discord server):

No watercooler complaints: you’re allowed to complain about something in direct proportion to how much work you’re doing to improve said thing.

There is nothing inherently wrong in expressing frustration with bad software, but if you don’t put a limit to the behavior, you risk creating an entire community whose favorite past time is whining about bad software and doing nothing about it. This is not a hypothetical, and in fact I believe this is a reasonable criticism to raise about the Handmade Network, the community that not coincidentally formed around Casey’s work.

So what is Casey’s talk truly for? Mostly to help him bitch about OOP on twitter more effectively.

Remember the windows terminal drama where Casey went to microsoft’s github organization, called a bunch of microsoft employees stupid there and on social media, and then made a PoC terminal emulator to prove that he could do better?

Some communities think of this story as a win by Casey. But I don’t, and we shouldn’t. And the reason is simple: are we today using his superior terminal emulator? Of course not, because it was just a proof of concept created to prove that microsoft is bad at software (no shit).

Instead look at what Mitchell did with Ghostty: didn’t start any beef with anybody and instead focused on creating a high-quality, multi-platform terminal emulator which many of us are using today.

We should want the Zig community to be full of Mitchells and, frankly, to be free of Caseys.

15 Likes

Thanks for the detailed explanation, I think I see now where you’re coming from.

I honestly didn’t know much about Casey so I was unfamiliar with all the context you mentioned. As I understand, your point is not about this talk specifically, but the general trend of expending a lot of time and energy criticizing OOP, a trend the talk is part of.

There is nothing inherently wrong in expressing frustration with bad software, but if you don’t put a limit to the behavior, you risk creating an entire community whose favorite past time is whining about bad software and doing nothing about it.

If I may rephrase your point to see if I’m understanding it correctly, it would be something like:

Even though discussing problems is a necessary step towards solving then, if you’re not careful, you may get tricked into feeling you’re making progress just by talking about the problem, which will prevent you from making actual progress.

Which is something I totally agree with and it’s something I’ve experienced a couple of times in corporate environments. Furthermore, I can totally see how a community may inadvertently start rewarding this behaviour, leading to the vicious cycle you mentioned.

My only slight pushback would be that in the case of design patterns, what “fixing something” entails is not as clear as with your terminal example, and may require talks that highlight what’s wrong with said pattern and what to use instead. On the other hand this doesn’t apply to Casey’s talk, since that’s not their main point; which in turn goes back to your original point.

3 Likes