And if you get rid of inheritance, there is very little left to distinguish OOP from procedural programming like one would do in C or Go. And this is the semantic problem: no one really agrees on what OOP is and proponents will rebut any criticism with “that’s not true OOP”. Any definitions of OOP that aren’t easily assailable are also indistinguishable from other existing paradigms.
Downvoters: i’m very interested in your opinions about why I’m wrong and specifically when you think inheritance is appropriate. Everyone says “there’s a time and a place!” but no one articulates when/where beyond cat/dog/animal toy examples.
Further, and more relevant to the thread at hand: it’s not clear to me that Kay’s notion of OOP considered inheritance to be a critical feature. To quote him:
> I felt somewhat the same way about inheritance as I did about types, in that both needed to be a lot better than they were in order to pay for the overheads and pitfalls of using them.
Objective-C[0] is C with Smalltalk's "notions of OOP." Objective-C has been the dominant programming language for making macOS and iOS programs since OS-X was first released. Swift[1] is taking over the role Objective-C once held alone, but Swift's roots in Smalltalk's "notions of OOP" are easily discerned.
0 - https://en.wikipedia.org/wiki/Objective-C 1 - https://en.wikipedia.org/wiki/Swift_(programming_language)
But again, you're right: most of us aren't familiar with Smalltalk and so find the very idea of reading such papers daunting at best. I think I'll finally try it though ...it can't be that hard of a language to grasp and it may well lead to some insights about why OOP, as defined by Mr. Kay, is defined as such.
I absolutely agree that understanding Kay and Smalltalk can help one become a better programmer and give context into the history of OOP. But it can't be interpreted as anything other than a semantic deflection in the context of a response to substantial criticism.
* OOP is about message passing (where message passing is NOT method invocations)
* OOP is about message passing (where message passing can be method invocations)
* OOP is about encapsulation (never mind that most/all paradigms make extensive, idiomatic use of encapsulation--some OOP proponents suggest encapsulation implies constructors that do lots of work, take ver few arguments, and make the class virtually untestable, others argue that this is an "abuse" of OOP or "bad programming")
* OOP is about inheritance
* OOP is a Kingdom-of-nouns programming style (effectively Joe Armstrong's "You wanted a banana but what you got was a gorilla holding the banana and the entire jungle" observation)
For all of these definitions, I've heard many OOP proponents argue that these things are not true OOP (typically without rebuke from other OOP proponents in the forum, bizarrely).
In my opinion, OOP must be defined by the things that distinguish it from other paradigms. Considering encapsulation and method calls are both fundamental to other paradigms, these cannot be defining characteristics of OOP. Additionally, any defining characteristic of OOP must be shared by languages that are virtually universally recognized as OOP, which means that message passing in a non-method-call sense must be excluded. That generally leaves inheritance, "extreme encapsulation" (untestable constructors), and kingdom-of-nouns programming styles.
I don't think the "class-based" thing is meaningful because apart from inheritance there's not much to distinguish a "class" from a struct in Go or Rust (in both cases you can associate methods to the struct for interface polymorphism) which are generally not considered to be "OOP languages" (and Go certainly doesn't have metaclasses or metaprogramming).
> Static typing is also something that not in Smalltalk, but that shouldn't change the network shape of objects.
I agree that static typing is not a defining characteristic of OOP, and I've never heard anyone argue that it is.
I meant that the newer less-pure-OOP languages tend to be statically typed vs Smalltalk etc where objects have behaviours but not compile-time shapes.
[0] https://en.wikipedia.org/wiki/Dynamic_dispatch#Dynamic_dispa...
When you say "there are virtually no valid uses of (implementation) inheritance" ... how do you expect the thousands of us using Django to respond to that? A link to the Django framework? To defend Django? What is the point?
You're right, maybe python's object model could have instead been implemented like Go's struct but it wasn't.
The former is mostly about invoking a type operator / metaclass [1] to construct a model class from your declarative specification.
I don't know what the latter is about. I think deep inheritance (where deep means like "more than 2") are virtually always a mistake. Stuff like toolkits that go Object>Widget>AbstractButton>PushButton might be an exception but I'm not entirely sure, there's probably a better way.
[1] I think metaclasses aren't type operators in the strict sense, because they're not handed a finished type, but rather the declaration of a type, and then create a type. Maybe there's a word for that.
class Iterable { ... }
class Tree extends Iterable { ... }
class SortedTree extends Tree { ... }
class Map extends Iterable { ... }
class HashMap extends Map { ... }
class InsertionMap extends Map { ... }
class BiMap extends Map { ... }
Need more examples of "valid uses of (implementation) inheritance"?> And if you get rid of inheritance, there is very little left to distinguish OOP from procedural programming like one would do in C or Go.
No. To make OOP indistinguishable from "C or Go", you would also need to eliminate at least; encapsulation, composition, access control, and compiler provided dynamic dispatching.
That’s easily achieved with plain interfaces. It’s not obvious to me at all why I would want to use inheritance instead of interfaces, especially because you elided the class bodies.
> No. To make OOP indistinguishable from "C or Go", you would also need to eliminate at least; encapsulation, composition, access control, and compiler provided dynamic dispatching.
C and Go have all of those things except that C doesn’t have “compiler provided dynamic dispatch” and I’m not sure how “access control” differs from “encapsulation” (access control is just public/private/etc, right?).
* encapsulation: in C things in the header files are “public” while things in the c files are “private”. In Go we have private/public struct members.
* composition: both C and Go have structs
* compiler-provided dynamic dispatching: Go has interfaces and closures. C doesn’t have this provided by the compiler but you can implement them yourself easily enough. You lose out on some type safety, but that’s no worse than a dynamic OOP language and if you care about safety you probably aren’t using C anyway.
I probably agree with the widget library example, but even here a widget library is just one way of implementing a GUI toolkit and perhaps it’s just the emergent result of an OOP-based approach (and consequently there are some really brutal tradeoffs in using a widget-based approach for a toolkit). To that point, with respect to general drawing libraries, I don’t think that OOP/inheritance yields a more elegant design than a reactive or intermediate mode approach (perhaps these terms only apply to GUI, but I imagine there are parallel terms for graphical APIs in general).
Even though I concede narrowly on the widget GUI library point, these libraries are so very rare that I don’t think it’s a very compelling case for OOP proponents. I suspect they’d like to argue that there are appropriate uses for inheritance in most applications and not just the odd GUI library. Otherwise I don’t think it even merits first-class language support (why bother with an `extends` keyword if it’s only going to be useful in the rarest of libraries?).
Read a fucking book, instead. David West’s Object Thinking, for example.
Thank you for clarifying that your downvote was definitely not an emotional overreaction. :)
Smileys don’t turn snide into humour, so now you can add “naked ad hominem” to the litany of downvote attractors.
.
.
.
.
.
:)
Further reading: Refactoring (Fowler), Smalltalk Best Practice Patterns (Beck).
I recommend not making any more false statements.
Experienced programmers will manage to keep that complexity creep under control for longer and smarter programmers will manage to keep working on complex systems that lesser peers would have no chance to understand.
But eventually, unless the software has a very clear functional boundary which is often not the case for business software, software will start to become increasingly complex and dev velocity will slow down, quality will drop... I've seen this happening at all skill levels regardless of the languages and paradigms used.
This. I always love toy examples that look so nice, concise, and elegant. Until you add proper error-handling and corner cases that is; then all of a sudden it doesn't look half as concise, elegant, and beautiful anymore...
"It is not the tools we use that make us good, but rather how we employ them."[0]
0 - https://en.wiktionary.org/wiki/a_bad_workman_always_blames_h...