(Round 1 Prompt, pasted)
I am looking for a short but precise definition of Object-Oriented Programming (OOP).
What should the definition of OOP cover?
- Languages or subsystems of languages that the authors, the public, and experts agree is OOP, whether the languages are popular or unpopular, whether academic, industrial or hobby projects.
- Languages that DO support design patterns and programming idioms and styles associated with OOP.
- Languages that had OOP features added, but only after the features were added.
What should the definition of OOP not cover?
- Languages or subsystems of languages that the authors, the public, and experts agree is not OOP.
- Languages that do NOT support design patterns and programming idioms and styles associated with OOP.
- Languages that had OOP features added, before the features were added.
As for edge cases of OOP, the rule-of-thumb for language constructs that differ from the baseline expectations of OOP should be whether these alternate constructs enable the direct expression of the usual OOP patterns, idioms and styles and more, or whether they fail to support a non-trivial, crucial subset of these patterns, idioms and styles. Being more expressive than OOP passes (the language supports a superset of OOP), being less- or differently- expressive does not (the language only supports a strict subset of OOP). Beware though to not be so permissive regarding such "expression" that any Turing tar-pit passes, including all the languages that we want not to cover above.
A good definition for a concept is:
- Meaningful: it provides information necessary and sufficient to delineate the concept. It must crucially reject what is outside the concept as well as accept what is inside.
- Clear: it relies on well-understood unambiguous words and preexisting concepts, and provides criteria that are objective (as much as can be). It is more important to have a clear story about what the concept means than a clear Yes/No answer to every question. Some questions are bad and should be rejected.
- Informational: it relates a concept at some level of abstraction to its manifestations at a slightly lower level of abstraction. The definition might invoke concepts at the same level as the one being defined, but only if they are simpler than it, and themselves have good definitions that are reasonably well-known. At times, it can be indeed be most enlightening to decompose a concept into simpler independent concepts of which you give the definition, than to give the combined definition without decomposition.
- Consistent (with itself): it does not contradict itself or lead to absurdities if taken seriously.
- Relevant (consistent with common knowledge): it must generally match the lore commonly associated to the concept. A good definition can, at times, disagree with common opinions and intuitions, but not too often (or else it is something else being defined), and not gratuitously (there must be a conceptual payoff to the cost of this disagreement). Now of course, if the common lore contains mutually contradictory "knowledge", then, the definition must make a choice, and reject some of that "knowledge", or contextualize it to a subset of the concept being defined, etc.
- Productive: the definition if truly great can lead to new discoveries that were not possible before the concept was made clear; it can illuminate parts of the conceptual space that were left out by the fog or the set of bad definitions that preceded it.
- Constructive: an truly great definition provides the conceptual bricks and the orientation that will help who understands it actively wrestle with the concept and act on it.
- What someone who understand both the theory, practice and implementation, the how, the why and the what for, did say, or would say.
The following are clear symptoms of a bad definition:
- Mumbo-jumbo: the definition uses buzzwords and ill-defined terms that don't actually enlighten.
- Appeal to uncommon knowledge: sometimes there's some useful text that has nice names, formulas and definitions that you may want to cite, but since the reader can't be assumed to know those texts, these names or formulas only make a definition worse, even though they may deserve to be added in comments.
- In-joke: Combination of the above, where the uncommon knowledge you appeal to is actually jargon and slogans from people living inside some bubble, which won't help any outsider understand the target concept.
- Ambiguity: the definition is unclear, doesn't let who uses it distinguish between what the concept covers or doesn't.
- Enumerations: the definition contains a haphazard enumeration of further concepts, instead of a clear criterion for what is or isn't it in. However, enumerations are conceivably alright if they are indeed essential to the concept. A good criterion is whether the enumeration is exhaustive, or whether it is advantageously replaced by a generalization (and may or may not have been identified and named previously) that would open a set of further possibilities beyond those enumerated. Maybe some of the enumerated possibilities are only special cases of others and can be dispensed with.
- Too Long: the definition contains extra words that are not necessary to the meaning, that only add noise or ambiguity.
- Too short: the definition leaves out words that are necessary to capture the precise understanding of the concept.
- Overshoot: the definition covers extra ground that should not be covered by the concept.
- Undershoot: the definition leaves out ground that should be covered by the concept.
- Appeal to authority: repeated because some pundit said it, even though it's not a good definition.
- Ignorant: could be said by someone who understands part of the topic and might even be an expert at that part, but not by someone who truly understands the theory, practice and implementation.
- You should consult with relevant literature, and at the end include bibtex for the papers you found truly worthwhile, with doi and url where applicable, (use KEY=VALUE without space separation around =). Prefer earlier variants of a cited article, to help establish priority of ideas.
- Webpages may also be cited if they truly bring key ideas not found in contemporary literature.
- Be not automatically satisfied with the "best" definitions and explanations already found in literature. They can be great starting points, but try to extract their essence Surely, if the literature already contains a great definition, that would be great news indeed, and worth citing.
- Much of the existing literature is just bad, or too biased, or partial, confusing whatever subset of the domain (or sometimes, even, disjoint domain) the authors are interested in.
- Each "mostly good" definition that misses out something, each pair of definitions that do not perfectly overlap, is a great opportunity to explore the concept that was missed.
- Do not expect a better definition than can be simply searched for without doing a deeper analysis of these concepts than those who issued those not-so-good definitions.
- Researchers, users, implementers, observers, all have their own biases, that may make their "definitions" or explanations good and bad in different ways. So have artists, streamliners, analysts, or visionaries. Hopefully, your definition will satisfy them all, though it may have to be differently explained or qualified to section of the public.
- The most popular, most prolific, most cited, loudest, richest, earliest or latest expert, most celebrated, edgiest or most moderate expert is not necessarily the best.
- Even great authors have blindspots, that do not diminish their greatness, and even less-than-great authors have deep insights, that do not diminish their failures, and you should keep and amplify the good and filter off or otherwise amend the bad.
- Key insight may be found in less-known authors, old or recent. But the more obscure the work, or the more again-the-grain, the less attention to authority and the more to rational content.
- If many people reinvent some concept independently, that's a good sign that it's important and needs to be further examined.
- If you find a source whose conclusions match your emerging answer, cite it for priority and confront it—but your deliverable must still contain a derivation of the answer from the criteria and the evidence themselves, one that would survive the deletion of that source. A conclusion supported only by citation, with no such chain, counts for nothing here.
You'll find that to well-define a concept, you may have to understand a lot of other related concepts, a (hopefully small) number of which may have to be included in the final definition. The criteria for a good definition recursively apply not just to the target concept, but to all the concepts at stake, and especially those that will be part of the final definition. Don't hold the other concepts you introduce to a lower standard of definition than the target concept.
- Clarifying away the emotion is the very goal of a good definition: whereas the common understanding of target concept is based on intuitions, and loose sets of subjective perceptions that do or don't add up and vary with each individual, a good definition by contrast provides a common ground based on objective criteria.
- A gradedness of membership into a wishy-washy emotion that things can more-or-less fit is a total failure of a definition, unless of course the concept is intrinsically defined by some kind of objective real numeric measure with membership as a threshhold (e.g. level of neural activation for the perception of primary colors).
- Instead of one wishy-washy graded concept (an emotion), better to have if necessary a gradation or hierarchy of clear-cut concepts, with stricter or looser sets of criteria, but each set well-defined, with each of its criteria well-defined. That's perfectly fine as a concept need not be "atomic" and isolated.
- It is possible that you would find that what looked like a single concept, under a common word or expression, actually means multiple different things, maybe related, yet distinct enough to not be usefully unified as a single concept. At that point, you should clearly identify and separate those concepts, give them separate names with separate definitions.
- Often extant literature will contain honest surveys, from which concepts and names should be reused. Existing surveys are not perfect though, their concepts may not be defined or delineated properly, the names they give may be unambiguous in the context of the survey but not outside it. Do not blindly take any such survey, as great as it may be, as too much of an authority. But do not gratuitously reject their suggestions and invent new names or variants of existing names unless necessary for disambiguation.
- Try to find the best names, minimizing ambiguity and misleading connotations, and choose names what will require the fewest overall explanations, where pointing to extant literature is a valid explanation where said literature indeed contains good definitions.
- Do not hesitate to qualify a word to denote a precise concept (not just a widget, a FOO widget), while keeping the unqualified word for the most general concept (a FOO widget is always a widget, not the other way around). Outlier concepts should have longer names than common concepts, unless they somehow are the heretofore unrecognized key to understanding the common concepts.
- Try to use the unqualified names for the general concepts closest to the target concept, and use qualified names for more specialized subconcepts, and altogether different enough names for more general concepts than those you will use in the definition. Unless perfectly good conventional names already exist, that you should then reuse, whichever way the qualifiers go.
- You will most likely have to identify concepts adjacent to the one you must define, yet distinct from it, before you may fully understand it, and be able to best define it.
- When you identify an important concept, it becomes just as important to name it and define it, with the same criteria for a good names and good definitions.
- In particular, if an important definition has several clauses, it may be worth it naming each of the criteria separately.
- Adjectives and qualifiers added in a definition can implicitly be clauses of their own that you must also identify as concepts. A good question is often "as opposed to what?", which often hides another concept being excluded by the attempted definition: should it indeed be excluded, of is the qualifier superfluous and unnecessarily restrictive? Or maybe the implicit concept, once named, can help understand other parts of the concept map?
- Similarly, hunt for subjective terms in definition that will not be the same for all participants (knowledge, beliefs, anticipations, intentions, expectations, obviousness, convenience, past or future participation, context, etc.). Make the participant explicit, and seek a higher conceptual level where a more objective or at least inter-subjective concept emerges from the interactions between participants.
- After you identify and name an important concept, do a quick review of the extant literature about this concept to refine your concept map, and maybe refine your names, too.
- These concepts may be specializations or generalizations of the concept you seek to define, involving more or fewer criteria, and useful in themselves. Or they may differ in subtle ways. It is highly likely that many authors in the literature will be confused between adjacent concepts, and your goal is precisely to tease apart those concepts.
- Beware that “taxonomy is the death of science” (Whitehead): identifying and naming concept for the sake of giving names is the opposite of making a topic understood.
- The purpose of exploring adjacent concepts is to better understand the target concept.
- As your understanding improves, you may have to refine concepts, reorganize them, and revise your taxonomy.
- Speaking of taxonomy, be very careful that fields of enquiry for which a concept matters will naturally fragment into further subfields and schools of thought over time.
- The people who study a concept will thus often use different taxonomies that are incompatible and contradictory with the taxonomies of other people; even the same people will use different, evolving taxonomies over time.
- Each subfield or school of thought tends to have their own insights, while often lacking the insights of other subfields and schools. These insights should be neither overstated nor ignored. They may lead to a ramification of related concepts that may be important to fully understand before the best definition of the target concept may be achieved.
- Thus, depending on context, the same names will be used to denote (sometimes subtly) different concepts. The same concepts will be denoted by different names. Be extremely careful not to be fooled by this effect.
- If the discrepancies between taxonomies can be confusing with respect to the meaning of one word, they can be a mine of hidden concepts for who is willing to carefully compare the taxonomies: the differences can be unrecognized concepts of momentous importance, or irrelevant distinctions that when abstracted away can lead to more general concept that simplifies the concept map.
- Make your own taxonomy if need be, and maintain a mapping with existing ones that matter.
- In establishing your taxonomy, seek conceptual clarity and simplicity first, compatibility with prevalent or relevant taxonomies second.
- Importantly, make your own ramification of concepts (that can change name with taxonomies), and carefully consider but do not blindly accept existing ones.
- The better surveys out there make for great starting points, but should not automatically be considered be-all-end-alls.
- It is actually great if the intellectual field where the concept lives has a wealth of well-identified, named, other concepts not necessary for this delineation; but it is actually bad if you need lots of intermediate concepts just to get to the delineation itself.
- Sometimes you do need to explain a lot of intermediate concepts to precisely define the target concept, and its final definition is more complex than expected; sometimes on the contrary, the conceptual exploration leads to the discovery of a generalization or change of frame that can drastically simplify the final definition. Clarity is more important than simplicity.
- So do not explore too deep when the exploration won't lead to clarification, but still explore one or two layers deeper than what led to inferior definitions.
- By the time you reach a definition, you must trim the taxonomy so you only exhibit the scaffolding of intermediate concepts strictly necessary to offer a precise definition of the target concept.
- A good definition must minimize the overall size of the definition including this scaffolding.
What are acceptable edge cases either way?
- When authors, practitioners, experts, observers, etc., disagree with each other about whether something fits the concept or not.
- When the candidate manifestation is so confidential that what "consensus" there might be is not significant.
- When the claims are interested, e.g. marketing hype by an industrial vendor, a mercenary consultant, or even an academic at a time when the concept is trendy enough it can lead to increased funding. Interested claims need not be false, but should tend to err on whichever side is in the interest of its author.
- When the claims are made by fringe authors, sometimes even deservedly celebrated experts, who dissent on a given point with the rest of the mainstream. The expectation would be that these authors are likely cranks or at least wrong on that point, but they may be unsung geniuses with undeservedly ignored insights.
- There can be plenty of honest mistakes even among experts in the field, and even more so among those who are only experts of a very narrow subfield, sometimes only of a single topic in the field (e.g. one programming language or software product). Disagreement is not an indictment, agreement is not an endorsement. Though often they go together.
- Edge cases, including, sometimes unsuspectedly, widely assumed claims, can thus lead to smaller or bigger surprises, wherein some weaker or stronger expectation is falsified after careful observation.
Edge cases should be independently confirmed (or rejected) based on first principles. The greater the discrepancy between observation and expectation, the greater the surprise (greatest if the edge case was not suspected), and the more new information is brought by the edge case. This is a great opportunity to refine and test these “first principles” that underlie your definition. After resolving these edge cases one way or the other, and examining the underlying reasoning offered to explain those choices, does accepting or rejecting the claims at stake lead to a better or worse definition?
More generally, insight is usually gained at the margins:
- It would be extremely surprising if there were absolutely no surprises, no mistakes, no difficult edge-case, and if a simple heuristic could adjudicate every case without resorting to clearer principles than most common definitions are expected to provide.
- Looking at discrepancies between observations and expectations is exactly how better understanding is achieved compared to the raw expectations; how underlying structure can be discovered that was not visible or at least not obvious in the main of the concept.
- Insight may be found in either explaining or explaining away the subtle differences between very similar presentations, or the not-so-subtle differences in very different ones.
- Each time your understanding leads to adding or changing criteria to a concept definition, you should examine whether the new criteria contradict previous ones, or makes some of them redundant, or is redundant with them, or whether some criteria can be happily combined and simplified, etc. Each criterion in the final version should be simple and necessary. You may make several attempts and refine or correct them.
- Once you have identified the distinction between adjacent concepts that many confuse, or the decisive criterion that allows you to solve an edge case, this is a great opportunity to further explore and understand the concept that lied at the discrepancy between understanding and misunderstanding, and map it.
- If an edge-case potential manifestation of the concept differs from baseline expectations by its attributes leading it to be able to more than pass the conceptual criteria, then of course it should count as passing, and if the differences lead to not passing all criteria, then of course it should count as not passing.
- Those unusual cases can help you refine what is the essence of the concept, by stripping its contingencies and going for the essentials.
- The common case might only be the simplest/cheapest/earliest-found/most-popular case, and not the general case.
- Keep exploring these cascading differences as long as you make progress, and that progress leads to notable improvement to your proposed answer.
- It is better to define concepts with shorter names in terms of their more general case, and to have separate concept with a longer, qualified name for the special case.
- Nevertheless, let's keep the target name for the target concept, even if we find that somehow it is "only" a special case of something else, that then deserves a different name.
Once you have a pretty good informal understanding of a concept, you can deepen your understanding by seeking a minimal formal model of said concept.
- It is pointless and a waste of time to seek a formal understanding of a concept before you already have identified the concept and given it a satisfying informal definition.
- However, once you have such a satisfying informal definition, a formal model can yield a lot of insight about things are actually equivalent, or analogous, and things that are very different (indeed belonging to incommensurable types or categories).
- A formal model should use suitable logic that only as rich as strictly necessary to formalize the concepts at stake. You should handwave it at first to see what capabilities you actually need or don't need in the end (classical, linear, temporal, epistemic, probabilistic, etc.)
- The computational side of a logic system is usually a variant of the lambda calculus, especially when discussing software. There isn't really a canonical "the" lambda-calculus, so pick the most appropriate variant carefully. With great power come great responsibility.
- Look at the patterns of your λ-terms, the types that they correspond to; the constant combinators by which terms are combined or transformed: for terms without combinators are just a chaotic gas of non-interacting atoms; it's the interactions between those terms that are the structure of the domain. What are the kinds of terms at stake, the signatures of useful operators?
- Can your presentation be reduced to a small kernel? Can you maximally eliminate redundancy, generalize your terms, etc.? If your simpler concepts are too complex, the complexity will percolate to larger concepts, so really try to simplify them away.
- Simplest in the historical context of invention and/or simplest in common informal models is not quite the same simplest in the context of logic and formalism. Prefer the latter, it's more enlightening. Which presentation has the fewer concepts and/or rules?
- Every kind of term and every combinator in your model must be defended: exhibit a case that dies without it, or else first try to exhibit it as a degenerate or special case of another, and eliminate it. (This is the same rule as for enumerations within definitions, applied to the model's own inventory.)
- A model is not complete until you have checked, for each manifestation you classify, how each entity and operation of the model is realized there: directly denotable and computable by programs? present only at some earlier stage (design time, compile time, inside the implementation, in the programmer's head)? several model entities merged into a single realization? absent altogether? These realization patterns are data: recurring profiles may be concepts worth naming, and differences of profile may explain differences in power between manifestations.
- Check whether the model applies to its own machinery: if the entities of your model are produced or transformed by something of the same shape one level up, the model should say so. Meta-level self-application of the model is a test of a model's closure, not a mere curiosity.
- The proof of the pudding of a model is that it is executable—and better, already executed: look for systems in the wild, in any industry however remote from the concept's academic home, that implement your model nearly as-is. Search where the purpose is the daily job, not only where the concept's name is the daily word. Independent reinvention is confirmation.
- Discrepancies between model and reality are gaps to account for, sometimes in the model, sometimes in the concept map itself.
Once you have precisely identified a concept, explored the surrounding conceptual map, and found a satisfyingly simple definition, your task is not over yet: you can try to relate the concept identified to its purpose, and give an even better definition in terms of the best way to achieve said purpose; or maybe the best way to achieve it given some constraint or strategy (assuming the concept indeed corresponds to the solution to a problem).
Why did anyone bother with the concept? What purpose does it serve? What problem did it solve? Did it improve some economic efficiency or biological fitness? How does that compare to the adjacent concepts from which you distinguished it? Was it the best, simplest or only solution to the problem? Can you conceptualize and appropriately narrow that problem such that the target concept is indeed the best solution? Does that lead to a simpler definition of the target concept? Ask also what the naive or previously available solution to that problem was, and what constraint made it unavailable, forbidden or insufficient: the content of a concept is often the exact shadow of that constraint. These problems and goals should necessarily be at a somewhat more abstract level than your precise definition, or they do not take the definition to to the next level.
In the case of concepts with an economic efficiency or biological fitness, etc., you may also climb the conceptual ladder one more rung, and look at the phenomenon and its effects from the point of view of the wider society or ecosystem. Often the details at the individual level also follow from a simpler more abstract definition at a higher level. But maybe not. Don't use a definition at a higher-level if it makes the explanations more complex. Each change of point of view has to earn its cost.
In pioneering for new concepts, the wherefore (what you want) precedes the why (how things fit together) that precedes the what (the solution offered). But in analyzing and defining an existing concept, the what (the concept you're trying to understand) precedes the why (how things fit together) that precedes the wherefore (what you want that it brings you).
For the sake of this exercise, please iterate a loop wherein:
- You try your best to organize your ideas from memory (closed book); apply all the criteria below to make sure your answers or as good as you can make them; loop several passes in step 1 as long as you make notable progress.
- Print your status so far: your best answer(s), explanations, notable changes from previous pass, and dissatisfactions.
- If you think you need additional information to improve your answers, Do a search for bibliography, articles, keywords, taxonomy, etc. (open book) You may use agents or forks for gathering information and summarizing findings. Then go back to step 1 with your new findings.
- When you are satisfied that your answer is good enough (despite any minor disatisfaction on non-essential points), carefully check the answer against the success criteria, and against the test cases that you came up with. If it appears not so good after all, go back to step 1.
- Print your final answer. Stop.
Round 1 Response by Fable 5
Pass 1 (closed book)
Candidate definitions from memory, and what's wrong with each:
Emerging synthesis. Run the user's own rule of thumb — "does the language directly express the usual OO patterns and idioms?" — over the contested cases and see where the fault line falls. Strategy, Observer, Composite, State need only interfaces + runtime dispatch. Template Method,
supercalls, mixin layering, framework hot-spots need something more: a method defined in one place must, when it calls a sibling operation on itself, reach the overriding version supplied later. That property — late binding of self, a.k.a. open recursion — is exactly what Go embedding lacks (an embedded method never re-dispatches to the outer type), what Rust lacks, what VB6 lacked, and what Ada 95 and Fortran 2003 gained at the precise moment the lore started calling them OO. The contested cases sit exactly on this boundary. That is strong differential evidence.Draft criteria (each named, each to be defended):
Classes, prototypes, message syntax, single vs. multiple dispatch, static vs. dynamic typing: implementation choices, not the concept. Object identity looks derivable rather than primitive: once representation is hidden (E) and state may mutate, reference identity is the only coherent sameness left; immutable objects (Java's
String) remain objects, so identity is a corollary, not a criterion.Dissatisfactions after pass 1: (a) verify the Kay quote and the CLOS tension; (b) check whether any survey already did this decomposition (I recall a CACM study surveying definitions); (c) confirm the formal side — I believe the Abadi–Cardelli ς-calculus has exactly three primitives matching E/D/O, and Cook–Palsberg model inheritance as fixpoints of generators, which would make the definition's minimality checkable; (d) pin citations and DOIs.
Open book# Pass 2 (closed book, integrating findings)
The open-book round confirmed the map and sharpened three things.
The literature's state. Cook's OOPSLA 2009 essay argues that even after decades of research, the two forms of data abstraction — abstract data types and objects — remain widely confused, and his object concept (a value known only through its operations) is the cleanest foundation for criterion E. Armstrong's CACM survey derived the "essential elements" of OO by analyzing the existing literature, distilling eight recurring "quarks" (object, class, abstraction, encapsulation, inheritance, message passing, method, polymorphism). This is valuable as evidence — it shows the field converged by frequency-count on an enumeration, precisely the bad-definition symptom to overcome: her eight quarks mix essentials (encapsulation, dynamic method binding, inheritance-as-capability) with mechanisms (class, method, message) and with a term ("abstraction") too generic to delineate anything. Kay's first-hand definition — OOP is only "messaging, local retention and protection and hiding of state-process," plus extreme late binding of everything — maps almost term-for-term onto E (local retention/protection/hiding), D (messaging as late-bound operation selection), and O (late binding "of all things," including self). So the inventor of the term, the semanticist of inheritance (Cook), and the mechanism-agnostic analysis of inheritance by Black, Bruce and Noble in "The Essence of Inheritance" independently triangulate the same three-part core. Independent reinvention is confirmation.
Refinement 1 — dispatch belongs to the participating objects, not "the receiver." The CLOS edge case forces this generalization: generic functions select methods at run time on all arguments' classes, and CLOS is OO by universal consent. Single-receiver dispatch is the common special case, not the concept. This also quietly fixes Kay's formulation, which taken literally excludes CLOS. Multiple dispatch is strictly more expressive — by the brief's superset rule, it passes.
Refinement 2 — "directly supports" must itself be defined, or every Turing-complete language passes. A language directly supports a construct when the language provides the construct's machinery once and for all — its instances are denotable, composable values, usable without re-erecting the mechanism at each use site or performing a whole-program transformation. C programmers encode objects (structs of function pointers,
selfpassed by hand, as in the Linux VFS or GObject); C does not directly support them, because the dispatch and self-binding machinery is rebuilt manually each time. This clause is what excludes tar-pits while letting the C encodings serve as evidence for the model (below).Refinement 3 — identity is a corollary, not a criterion. Booch-style definitions list "identity, state, behavior." But once representation is hidden (E), behavioral equivalence is the only intrinsic sameness; languages with mutable encapsulated state must then supply reference identity as the practical stand-in. Immutable objects (Java's
String) remain objects. Identity falls out of E plus mutability; adding it as a criterion is redundant.Edge cases adjudicated
Go and Rust — E ✓ (methods, unexported fields, interface/trait abstraction), D ✓ (interface values,
dyn Trait), O ✗: Go's embedding forwards calls without rebinding the outer receiver, so a promoted method never re-dispatches to an override; Rust has no override at all. Template Method,super-chains, mixin layering, framework hot-spot patterns lack direct expression. Verdict: object-based, not object-oriented — and gratifyingly, these are exactly the languages the public contests (the Go FAQ itself answers "yes and no"). The live fault line of public disagreement falls precisely on criterion O, which is strong evidence O is real and criterial rather than incidental.VB6 — E, D via interfaces; no implementation inheritance, no late-bound self across a derivation: object-based. Matches the contemporaneous complaint that it wasn't "truly" OO. Ada 83 → Ada 95 and Fortran 90 → Fortran 2003: the added features (tagged type extension with overriding dispatched primitives; type-bound procedures with override) are exactly D and O — the lore's before/after judgment flips exactly when the criteria are met. JavaScript and Self: classless, but delegation gives O (
thisis late-bound through the prototype chain) — always counted OO, so classes are not essential; Wegner's 1987 ladder must be amended on this point. CLOS: D generalized, O via inheritance pluscall-next-method; E supported (accessors, packages) though not enforced — but C++friendand Java reflection also pierce encapsulation, so the criterion is direct support of abstraction, not unbreakability. OO. Erlang: encapsulated processes, run-time substitutability of any process behind a message protocol — E and D at process granularity, no O; also,receiveis client-side case analysis inside the process. This is the actor model: an adjacent sibling concept, not a subset or superset — which explains why the Kay lineage calls it deeply object-oriented while mainstream taxonomy doesn't. Naming the sibling dissolves the dispute. Haskell / ML: the abstraction unit is the type or module, not the value; heterogeneous substitution and open recursion exist only as encodings (existentials, records of closures, hand-tied fixpoints). Per Reynolds and Cook these are the dual discipline — ADTs — and the consensus "not OO" verdict is principled, not prejudice: adding operations is cheap there, adding representations is what's cheap here.Minimal formal model
Abadi and Cardelli's ς-calculus is the minimal executable model, and its inventory audits the definition. It has exactly three constructs: object formation
[lᵢ = ς(xᵢ)bᵢ](a record of methods, each closed over its own self-parameter — this is E: the only thing a body can touch is reached through self), method invocationo.l(the body run is the one o itself carries — this is D), and method overrideo.l ⇐ ς(x)b(producing a modified object whose other methods' self now refers to the modified whole — this is O). Drop override and you get the object-based fragment (the Go tier). Drop the self-binding and records of methods degenerate into plain records of functions — the ADT/closure world. Each construct has a case that dies without it; none is a special case of another. Equivalently, at the class level (Cook–Palsberg): a class is a generatorG : Self → Record, an instance isfix(G), and inheritance is transformation of the generator before taking the fixed point — which is exactly why an override propagates into inherited code, and why "inheritance" without late-bound self (mere copying or forwarding) is not the same capability.Realization profiles are data. In Smalltalk, Self, and JavaScript, all three ς-operations are run-time denotable; in C++/Java, override exists only at class-definition time — the class-based/prototype-based split is precisely at which stage the ς-override operation is available. The model closes over itself: in Smalltalk and CLOS, classes are themselves objects made by metaclass generators — the machinery is in the model's own image. And it runs in the wild where the problem lives rather than the word: COM's binary interfaces, Unix VFS
file_operationstables, GObject — hand-built records of functions with explicit self, reinvented wherever independently compiled components must interoperate. Which points at the purpose.The purpose-level definition
Why did anyone bother? The problem: extend a system with new kinds of interoperating things without editing the code that uses them. The naive solution — a closed tagged union plus functions that case-analyze it — dies under the constraint that clients ship separately and cannot be edited (libraries, frameworks, operating systems, plugins: Aldrich's observation that objects become inevitable exactly where independently developed parties must interoperate through a service abstraction). OOP is the shadow of that constraint: E packages each variant's behavior with its data so a variant is self-describing; D defers selection to run time so clients stay closed while the set of variants stays open; O makes the cost of the n-th variant proportional to its difference from existing ones. Reynolds saw in 1975 that this is one pole of a duality — procedural data abstraction makes new representations cheap and new operations dear, ADTs the reverse — later nicknamed the expression problem by Wadler. OOP is the discipline that chooses the representation-open pole.
Check against the success criteria and stop
Meaningful: E∧D∧O accepts Simula 67 (whose
virtualis D and O born together, establishing priority), Smalltalk, C++ (in its virtual subset), Java, CLOS, Eiffel, Self, JavaScript, Python, Ruby, Ada 95, Fortran 2003, OCaml objects; rejects C, Pascal, Fortran 77, SML, Haskell, Prolog, SQL; and places every genuinely contested case (Go, Rust, VB6, Erlang) in a named adjacent tier rather than fudging a gradient — no wishy-washy membership, a ladder of crisp concepts. Clear: three named criteria, each defined via prior well-defined concepts. Consistent, and consistent-with-lore including the before/after flips. Productive: it predicts where objects get reinvented (interoperability boundaries) and explains the class/prototype split as a staging difference. Constructive: the ς/generator model is executable. Remaining minor dissatisfaction, acknowledged and accepted: whether O should be required rather than characteristic of full OO is where honest experts (Cook vs. Wegner's lineages) genuinely split; the taxonomy names the split instead of hiding it, which is the correct resolution of a real disagreement, not a failure to decide.Final answer
Object. A first-class value that couples a (possibly hidden, possibly mutable) representation with the operations on it, such that clients can use it only through those operations — a procedural data abstraction. (Corollary: since the representation is inaccessible, sameness is behavioral; mutable objects therefore carry reference identity.)
A language is object-oriented iff it directly supports building programs out of objects with all three of:
"Directly supports" means the language supplies the machinery (dispatch, self-binding, modification) once and for all, with objects as denotable, composable values — not merely that the machinery can be encoded.
A program is written in object-oriented style to the degree that its variation across representations is expressed by dispatch on objects rather than by client-side case analysis over a closed set of alternatives.
Taxonomy (each tier crisp): module/ADT languages (E's dual: type-hidden representation, static operation selection — ML, Ada 83, CLU); object-based languages (E+D — Go, Rust with trait objects, VB6, Emerald); object-oriented languages (E+D+O); pure object-oriented languages (all values are objects and all operations dispatch — Smalltalk, Self, Ruby nearly). Adjacent sibling: actor systems (E+D at process granularity, messaging asynchronous, no O — Erlang).
Purpose form (the same concept, one rung up). Object-oriented programming is data abstraction arranged for openness along the representation axis: the least discipline that lets a system acquire new kinds of interoperating components without modification of existing clients (E+D), at a cost per new kind proportional to its novelty (O). Where the dual constraint holds — a fixed set of representations but open-ended operations — its mirror image, the ADT discipline, is the right tool; mature languages support both, and the confusion between them is the root of most bad definitions of OOP.