Big if there. Most people do not mean Kays OO when they say OO.
I would suggest that if you asked people to define the term, Kay’s definition would likely be the single most common (even after normalizing variations in wording).
It would still only be a plurality, sure, but the remaining majority doesn't share a common understanding, either.
An example would be non-fragile ABIs (ObjC has this, C++ doesn't) or typestate/built in state machines (so you can't call methods if the object is in an invalid state for them). There's encapsulation at least, it's a start.
Fragile ABI is basically a C++ problem. Java has had a stable OO ABI for 25 years now. The .NET ABI has gone through a few iterations, but is stable now. Of course Microsoft also had COM, which is/was a stable OO ABI accessible to many languages including C++ and was arguably just a subset of the C++ ABI without templates.
In the AOT compiled work Swift now has a stable OO ABI (sort of). Rust is interested in getting one. Lack of a stable ABI is not an OO problem but more a problem of languages that are designed to compile ahead of time to native code and use native formats as their primary artifact format.
Most features OO has reduce complexity and bugs, that's why people use them. There's no comparison between a clean OO API and the de-facto standard state before that, e.g. POSIX, Win32, Carbon.
Why the past tense, when COM is the main way Windows APIs have been introduced since Windows Vista, as COM took over Longhorn OO ABI ideas?
Nowadays we just call it WinRT.
I haven't kept up much with Windows programming so lost track at some point of what their current-gen tech is and how it works. WinRT isn't just COM is it. It's custom languages, new app metadata formats and stuff. I don't see IUnknown in any modern Windows code samples.
C++ is more of a multi paradigm language where the designers (eg Alexandrescu) actually publish books telling you to focus on algorithms and generic programming rather than object trees. KDE/Qt reinvent messaging on top of the default OO, don’t they? There’s something about slots.
> There's no comparison between a clean OO API and the de-facto standard state before that, e.g. POSIX, Win32, Carbon.
Don’t know about Windows but POSIX and Carbon were as OO as they needed to be - a function where the first parameter is a “file” or “context” is being object oriented. There were actually several attempts to replace Carbon with more OO APIs, that used heavy implementation inheritance, like Taligent and MacApp and they failed because they were too complicated. Cocoa succeeded by using messaging and composition instead like Alan Kay wanted.
Don’t know about Windows but POSIX and Carbon were as OO as they needed to be - a function where the first parameter is a “file” or “context” is being object oriented.
Honestly I don't know of anyone, including the people who defined those APIs, who would call them object oriented. POSIX functions aren't even namespaced and routinely don't even take a struct as the first parameter. Implicit state is everywhere in POSIX, Win32 and I think also Carbon.
Cocoa succeeded by using messaging and composition instead like Alan Kay wanted.
Cocoa "succeeded" by being the official API of the first non-failed attempt at resurrecting macOS. On Windows, the API that "succeeded" was .NET which is a classical C++ type of OO. In practice, Objective-C caused a lot of problems for Apple. They would have junked it years earlier but Steve Jobs was wedded to it and couldn't understand why anyone wanted anything else. The moment Jobs died Swift was started as a project, and Swift does not have objc_msgSend at its centre, at least not if I understood the Swift ABI correctly.
The "messaging" concept caused problems in the following ways:
* Performance, despite objc message sending being heavily optimised.
* Bizarre semantics that led directly to horrible bugs, like sending a message to null being "valid" but returning junk if the return value was meant to be a struct.
* Difficult to optimise due to the dynamic language features, which are nonetheless hardly used (e.g. ability to redefine methods on the fly).
The latter problem is shared with languages like Ruby.
There's (at least) a third model IMO from CLOS & friends, such as Dylan, S4, and I'd argue Haskell Typeclasses. Not sure what I'd call it but it's the idea where you define data classes, generic functions, and then provide linkages between those data classes and the generic functions to give you methods on the state
Actually, if not for some historical accidents, we could have Dylan in place of Java today... I sometimes dream about such a world: functional core, CLOS-like generic functions and multimethods, sane multiple inheritance, syntax-case-like macros, native AOT compiler, sane module system... OpenDylan - the implementation I played with - is slow as molasses, but with even a tiny fraction of the work put into Java it could be made fast enough to rival C++. It's one of the most striking wasted chances in the history of programming.
Edited to add: Kay also frequently says he's a proponent of object oriented, not class oriented programming. Classes are just a means of organizing the code, objects and their relationships is what matters. In that way, modules in Elixir are not inferior to classes in single-inheritance OO languages: they offer the same level of sharing and composing code (via macros, defoverridable, and defdelegate). Add to it protocols, which can extend arbitrary types (modules) and you get quite nice OO toolbox to use in Elixir.
One source: https://hillelwayne.com/post/alan-kay/
Still, the definition Kay gave as late as in 1998 resonates with me the most:
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.
And this is almost exactly what Erlang implements: just add "asynchronous" before "messaging" and it fits perfectly.
- Main abstraction are classes (of objects).
- Concept of self-initializing data/procedure objects Internal ("concrete") view of an object vs an external ("abstract")
- Differentiated between object instances and the class
- Class/subclass facility made it possible to define generalized object classes, which could be specialized by defining subclasses containing additional declared properties
- Different subclasses could contain different virtual procedure declarations
- Domain specific language dialects
As that article clearly shows, at least once you’re past its clickbait title, Kay acknowledges his influences. That isn’t a lack of clarity, it’s an awareness that we all build on the effort of our peers and predecessors, that ideas do not spring forth fully formed from the void.
This does not discredit anyone’s work, far from it; context is an aid to understanding.
What I mean by lack of clarity is that Kay in 1998 thinks that messaging is the key idea, and suggests that was always the key idea. But none of the historical sources I've seen suggest he was clearly and consistently saying that in the 70s.
That's really a minor point, it does nothing to invalidate Kay's contributions. You can design a system that has value, and only later find the best way to talk about its value. That happens constantly: people create something and then end up saying "in hindsight, I got X right and Y wrong" or "back then, I knew this worked, but it was only later that I knew why".
It doesn't disprove the idea that focusing on messaging gives you the best version of OOP. It doesn't even disprove that "real" OOP is about messaging (though I think that argument has a high bar to clear--most terms are messy).
What it does disprove is that messaging has a right to be the core of OOP because Alan Kay defined it that way back in the 70s.
P.S. Maybe the title isn't ideal, but Hillel was literally reacting to someone who said Alan Kay invented objects: https://lobste.rs/s/8yohqt/alan_kay_oo_programming#c_5xo7on. Actually, that might be a better source than what I linked to, because it marshals more evidence that Kay was not consistently saying "messaging is what matters" during the 70s. He may have believed it, he may have said it sometimes, but he wasn't consistent about it.
Again, that's not a criticism of Kay, except the super mild one that his 90s/2000s memory of what he said 20 years earlier wasn't perfect. But I forget shit I said last week, so I'm not gonna judge.
Well, I think "messaging" is an abstract concept. It doesn't have rights, so there was nothing to prove.
Nevertheless, credit matters, because people matter, and do have rights. One of those rights is to have an opinion, including the opinion that messaging is the core of OOP.
> clearly and consistently saying that in the 70s
This is indeed a preposterous and unhealthy standard to expect of anyone, on any topic. It's the kind of thing that two-bit politicians like to dig up on each other, to nobody's edification.
We agree. No idea how I screwed up that sentence. The intent was "that messaging is the right core of OOP because", but it was awkward, and I spliced something together.
> It's the kind of thing that two-bit politicians like to dig up on each other, to nobody's edification.
This is a discussion of what a word means, not an attack on someone's character.
you can find his various comments here: https://news.ycombinator.com/threads?id=alankay
It has not solved the “minimum set of primitives that make OO tenable” problem.
C++ is likely the worst OO language in common usage and C++ developers rightfully avoid using its native OO functionality as much as possible. They will literally jump through hoops and write tons of additional boilerplate code to avoid exposing the language's OO functionality (doing what C++ developers call type-erasure).
C++11 didn't improve OO in C++, it gave programmers many features to avoid having to use it altogether.
Common C++ libraries like boost have an entire library dedicated to type erasure:
https://www.boost.org/doc/libs/1_75_0/doc/html/boost_typeera...
Facebook's Folly library also provides type erasure functionality:
https://github.com/facebook/folly/blob/master/folly/docs/Pol...
Google's Abseil is full of type erasure:
Here is Adobe's C++ library for type erasure:
https://stlab.adobe.com/group__poly__related.html
And here's a talk by Sean Parent about how Adobe uses type erasure to emulate runtime polymorphism without using C++'s native OO features:
https://www.youtube.com/watch?v=QGcVXgEVMJg
I suppose these are just some people somewhere...
classes, polymorphism, some level of inheritance, delegation, composition, builders, method dispatch, ....
What they are doing is implementing an ad-hoc version of OOP that forgoes using C++'s native OO feature-set. Native C++ OO clashes with modern C++, often creating a dialect that does not play well with resource management and common C++ idioms.
The type erasure libraries provide many of the traditional benefits of OO but allow you to retain value semantics (which native C++ OO does not).
My argument was never about OO as a general concept, it was strictly that C++'s native OO feature set is very poor and modern C++ allows developers to move away from that feature set.
To humor you... if I have a base class of type Animal and a derived class of type Cat, then making a copy of a Cat through a pointer or reference to an Animal results in object slicing which is not what you expect when you make a copy of a polymorphic object. Basically you only end up copying the Animal instead of the entire Cat.
https://en.wikipedia.org/wiki/Object_slicing
One of the motivating reasons to use type erasure is precisely to solve this issue, so that one can copy an Animal or assign Animals and treat an Animal as a value and copies work as expected.
When one copies a std::function or any of the type erased classes provided by the standard library, it just works as expected, without needing to consider lifetime issues, object slicing, C++'s complex rules about inheritance vs. virtual inheritance, and a host of other problems that don't mix well with other parts of the language.
The cost of type erasure is that it requires a lot more work on the part of the author. The libraries I linked to help alleviate most of the boilerplate, but as the examples demonstrate, there's still a lot of work that needs to be done to get it right.
First: I've done professional C++ development since 1996. Fulltime, with just a smidgen of Java in a couple of places. So your guess is completely mistaken, as is your opinion of where I'm coming from.
Second: The post I replied to never mentioned "polymorphic", so I interpreted "value" as your claiming that you couldn't treat a pre-C++11 class as a value type, which is clearly a bogus claim.
I do mostly embedded systems. I do use polymorphism, but most of my objects cannot be cloned (private, unimplmented copy constructor and assignment operator), and the only collection they live in is a fixed-sized array.
If I had to do your Cat example, I'd probably have Animal's copy constructor call a protected pure virtual clone() method. I understand the slicing problem, and that a slice is not what you want.
I confess that I don't understand how type erasure helps with the copying problem, nor how std::function uses type erasure.
>private, unimplmented copy constructor and assignment operator
If you're using C++11 or better, then avoid doing that. In modern C++ you declare those as deleted.
>If I had to do your Cat example, I'd probably have Animal's copy constructor call a protected pure virtual clone() method.
This would do absolutely nothing and once again, despite you claiming to have 25 years of professional experience in C++, I must shake my head to even hear such a thing.
All I get from this conversation is that you have a very antiquated idea of how to use C++ and have not kept up to date with modern standards. You mention the rule of 3, which is a pre-C++11 idiom and superseded by the rule of 5 with the advent of move constructors (or the rule of 0). Yet despite this you felt it appropriate to claim that since you personally have never encountered any recent advancement in C++ in the past decade, that it must be me who is distorting the situation.
It could not possibly be the case that the C++ of today is much different from the C++ back in 1996 when you started using it, nor could it possibly be that using C++ for embedded development represents only a tiny subset of how C++ is used, or that maybe you just aren't familiar with something because no one is an expert in everything and we have to prioritize what we spend our time learning. No... the conclusion you chose to go with is that I'm distorting reality because you happen to lack any modern knowledge about a technology that you claim to have 25 years of experience with.
Hate to break it to you... but it's not the 90s anymore.
I think there’s room for kitchen sink languages and also opinionated, minimalist languages.