News for hackers. Stuff that matters.
Re:OOP Is Dead, Long Live OOP by maxxxxx on Thursday October 18, 2018 @02:02PM (#18250571)
If we just had made inheritance as something to be avoided unless absolutely needed then OOP would have probably never got such a bad reputation. All the other concepts make perfect sense.
Re:OOP Is Dead, Long Live OOP by 3pt14159 on Thursday October 18, 2018 @02:56PM (#18251091)
I've found that inheritance is very useful in one situation, and adds nothing over mixins otherwise.

If a class does two broad things simultaneously then inheritance can work great. For example, a User class that inherits from a DB mapper class. I don't want to have to tell my class how to write a record to the DB. All that code can be centralized into one thing and then relied upon for its uniformity across all my models.

This isn't true the way most people use inheritance though. They do things like Sword inherits from Weapon and Weapon inherits from Item. But this just asks for trouble because as requirements get more complex there are more edge cases and the complexity bubbles up into overriding the inherited methods, which makes them less reliable from different calling contexts, or flipping the OO script and pushing class-based-if-statements in the ancestor class.

Then you step back and say "why did we make Sword a weapon in the first place?" and the answer was we had logic somewhere else in the code that did things like check if a user was armed. Well we don't need inheritance for that at all. We can use plain old methods and properties / duck typing.

Re:OOP Is Dead, Long Live OOP by Chabs on Thursday October 18, 2018 @03:09PM (#18251203)
Frankly, having User inherit from DBMapper is way more egregious in my eyes than Sword inheriting from Weapon.

It doesn't really matter because both of these things can be better solved using composition + traits/interfaces anyways.

Re:OOP Is Dead, Long Live OOP by hota_mazi on Thursday October 18, 2018 @03:41PM (#18251461)
Duck typing is the worst of all worlds, in my experience.

And in defense of inheritance, the Liskov Substitution Principle is extremely useful and makes a lot of sense.

If a function accepts a `Weapon` as parameter, surely you should be able to pass it a `Sword`.

Re:OOP Is Dead, Long Live OOP by TheOtherHobbes on Friday October 19, 2018 @04:28AM (#18255071)
The problem is that we're trying to formalise relationships that make perfect sense in natural language by assuming the same relationships make perfect sense in code.

"Sword" instances may have specific properties that make them incompatible with a "weapon" superclass. Is a broken sword still a weapon? How about a sword with no handle? Or a sword that has been magically transformed into a flower? Is that still a sword and a weapon, or is it now "really" a flower, and should inherit all flower methods while throwing away all weapon methods?

You can duck type and/or RTTI your way out of this problem, but you can't avoid the fact that traditional OOP is very bad at handling these "it depends" cases, because the only relationship it supports is a strict and static inheritance hierarchy.

Unfortunately many domains, including natural language, can only be described by mutable context-dependent relationships.

In the real world, swords don't turn into flowers, so you might think you're safe. (Except that you might want to include object mutability in a game...)

But in NL the meaning of a phrase can change according to social setting, unstated subtext, speaker gender, age, and even time of day. It's all context, and it can't be ignored without losing essential detail.

All current typing systems seem to be attempts to enforce limited-scope static relationships between opaque atomic objects with more or less static properties.

Mutable context-dependent relationships are everyone's worst nightmare in CS. Academic CS seems to have spent most of its career trying to pretend they don't exist, or if they do, to make them go away.

This is sold on the basis of making more reliable code. In fact it simply doesn't work elegantly for entire classes of problems, including many problems for which it seems to work just fine if you describe them in words, until you have to think about all the possible details.

The worst case output is intolerant brittle code with limited features, and the best is an encrustation of exceptions, edge cases, and work-arounds.

Note I'm not saying there's a simple answer, because there isn't. This is a research-grade problem, and it's barely been considered.

I am saying - beware of simple principles like LSP that claim to solve this problem. Because there are many situations in which they simply don't.

Re:OOP Is Dead, Long Live OOP by pwm on Thursday October 18, 2018 @04:37PM (#18251891)
The problem with LSP is that it is an incredibly hard property to prove (behavioural subtyping in general is undecidable). So in theory yes, it sounds great in practice with a sufficiently complex system good luck ensuring that you adhere to it.
Re:OOP Is Dead, Long Live OOP by humanrebar on Thursday October 18, 2018 @09:27PM (#18253687)
Except Firearms require the reload() method be called periodically between calls to use(). So now we have to think about whether Swords need an empty reload() method or whether there need to be separate Firearms and Blade interfaces based on Weapon.
Re:OOP Is Dead, Long Live OOP by hota_mazi on Friday October 19, 2018 @12:36PM (#18257910)
Yup, that's how it works. And why inheritance and polymorphism is so popular: it's powerful, easy to explain, and captures elegantly a lot of problems we need to model.

In contrast, non class based languages such as Haskell struggle to model problems that are trivial in OOP, such as how to reuse 90% of existing functionality but override 10% with more specialized behavior. Good luck solving that problem elegantly with type classes.

Re:OOP Is Dead, Long Live OOP by maxxxxx on Thursday October 18, 2018 @11:08PM (#18253990)
"Swords need an empty reload() method"

That always seems to the problem with deep hierarchies after a while. Suddenly you have something where one of the inherited methods shouldn't be there. You can't take it away so you have to do something clunky like throwing an exception or making it empty.

Re:OOP Is Dead, Long Live OOP by maxxxxx on Thursday October 18, 2018 @03:10PM (#18251216)
"adds nothing over mixins otherwise."

The funny thing is that languages like C# and Java abandoned mixins but kept deep inheritance hierarchies. When I did C++ more we used multiple inheritance a lot but with only one or two layers deep. This worked extremely well and now that that I am doing more in C# I miss it a lot.

Re:OOP Is Dead, Long Live OOP by fooyc on Thursday October 18, 2018 @04:20PM (#18251772)
> I don't want to have to tell my class how to write a record to the DB

You don’t need inheritance to achieve this.

Your User class contains data and probably some business logic. The fact that it’s going to be persisted in a database at some point is a detail that the class shouldn’t know.

Consider using the data mapper pattern (or an ORM implementing this pattern). In this pattern, your User object doesn’t even know it will be persisted. It doesn’t have any parent class. You just manipulate your entities like a graph of plain objects, and when you have finished you ask the data mapper to persist them. In my experience this is much better than what you are describing, which look like the Active Record pattern.

> If a class does two broad things

Doing this is a violation of one very commonly accepted principle: The single responsibility principle.

Re:OOP Is Dead, Long Live OOP by spdionis on Thursday October 18, 2018 @06:28PM (#18252741)
Active Record should be considered an anti-pattern and is definitely in violation of single responsibility at the least.

Myself, I wouldn't even put any business logic in the User object, except maybe representational logic (e.g. have a couple of helper methods that return multiple representation of the same piece of data).

One of the best things to do is separate behavior from data in the first place, which feels kind anti-OO philosophy, but is definitely easier to reason about and work with.

Re:OOP Is Dead, Long Live OOP by maemilius on Thursday October 18, 2018 @06:16PM (#18252647)
My understanding of SRP is that the _implementation_ of those two things should be separate, not the interface.
Re:OOP Is Dead, Long Live OOP by humanrebar on Thursday October 18, 2018 @09:35PM (#18253726)
Well, the I in SOLID is Interface Segregation, so there's a problem there too.
Re:OOP Is Dead, Long Live OOP by seanmcdirmid on Thursday October 18, 2018 @03:23PM (#18251332)
Mixin inheritance is also inheritance, just linearized multiple inheritance actually.
Re:OOP Is Dead, Long Live OOP by pitaj on Thursday October 18, 2018 @04:04PM (#18251661)
Mixins can be modeled as inheritance or as composition.
Re:OOP Is Dead, Long Live OOP by dragonwriter on Thursday October 18, 2018 @05:30PM (#18252310)
They can be modeled as inheritance or as composition plus delegation, but that's not saying much since inheritance itself can be modelled as composition plus delegation.
Re:OOP Is Dead, Long Live OOP by dvlsg on Thursday October 18, 2018 @04:23PM (#18251794)
I think composition and mixins should be kept separate. In my mind (and maybe I have an incorrect view of it), mixins throw a bunch of new properties on the base object, whereas composition keeps the original object encapsulated in a single property. Would you consider the second type to be a mixin? I've never heard it described that way.
Re:OOP Is Dead, Long Live OOP by seanmcdirmid on Thursday October 18, 2018 @04:10PM (#18251703)
Both Flavor-style mixins and Bracha style mixins utilize inheritance. All mixin definitions should fan out from that early work.
Re:OOP Is Dead, Long Live OOP by keerthiko on Thursday October 18, 2018 @03:32PM (#18251400)
I agree. As with most tools in programming, not every mechanism of a language should be employed aggressively unless it truly improves your application architecture.

Inheritance is very useful especially in game programming (in context of OP), and hardly ever anywhere else. In games it's useful to be able to pass around references to an object or have systems that manage pools of objects at exactly the hierarchy of inheritance that makes the most sense for the manager of that system. Not many other applications need to pass around objects between various hierarchical management systems as much.

I think inheritance shouldn't be taught in intro-level programming classes. It's presented as "how to do all things in OOP, shove all the things into multi-level child classes" when really it should be "here's an advanced concept for situational architecture optimization". It defeats the purpose when you do multiple levels of inheritance and no longer ever use the parent classes for anything.

Re:OOP Is Dead, Long Live OOP by goalieca on Thursday October 18, 2018 @04:43PM (#18251943)
> Inheritance is very useful especially in game programming (in context of OP), and hardly ever anywhere else.

This is because OOP is good at modelling objects and games are modelling objects.

Re:OOP Is Dead, Long Live OOP by hota_mazi on Thursday October 18, 2018 @03:38PM (#18251446)
Sure, the general consensus is that inheritance is better achieved through composition.

But let's be serious for a minute here: even regular inheritance has hardly ever led to the kind of nuclear disaster than most pundits claim.

It makes your code base a bit more unwieldy and a bit harder to evolve, but it's really not the end of the world.

Re:OOP Is Dead, Long Live OOP by jcelerier on Thursday October 18, 2018 @03:45PM (#18251496)
> Sure, the general consensus is that inheritance is better achieved through composition.

This sentence does not make sense. If you want to have a class composed of two other classes, whose behaviour is defined at run-time - say, a generic "Engine" object which is composed of a "GraphicsRenderer" and an "AudioRenderer" where the first one can be a D3D renderer or an OpenGL renderer and the second can be an XAudio or OpenAL renderer, you have to have inheritance somewhere, because you have to store at least one function pointer at some point. std::function in C++ is implemented with inheritance. Rust traits are based on inheritance. However you look at it, you can never completely "get rid" of inheritance if you want to hide both code and data behind a single pointer. Hell, even the linux kernel written entirely in C reimplements vtables by hand for device drivers because it makes so much sense.

Re:OOP Is Dead, Long Live OOP by hota_mazi on Thursday October 18, 2018 @03:54PM (#18251574)
You are confusing inheritance of implementation with inheritance of interface.

The consensus is to use inheritance of interfaces and use composition to implement the interfaces.

Hence my phrasing: "Inheritance is better achieved through composition".

Re:OOP Is Dead, Long Live OOP by marcosdumay on Thursday October 18, 2018 @06:41PM (#18252848)
> The consensus is to use inheritance of interfaces and use composition to implement the interfaces.

A consensus by the "maximization of boilerplate" rule.

Inheritance is the most powerful tool available at the OOP land. It's the one thing that FP languages still didn't replace with enough added advantages to make the OOP stuff look like a toy. So if you are programming in OOP while avoiding inheritance, you would be certainly better in another paradigm.

(And, of course, powerful tools are easy to misuse. That's no reason for forbidding them.)

Re:OOP Is Dead, Long Live OOP by mercer on Sunday October 21, 2018 @06:48AM (#18267454)
I'm not familiar enough to have a strong opinion on this, but the impression I get is that even the OOP camp (or thought leaders within those camps) seems to have abandoned inheritance in favor of composition.

Assuming this is the case: why do you disagree and what do you think is the cause of this difference in opinion?

Re:OOP Is Dead, Long Live OOP by CMCDragonkai on Friday October 19, 2018 @07:17AM (#18255825)
Check out extensible records or Nix language fix pattern for its attribute sets.
Re:OOP Is Dead, Long Live OOP by jcelerier on Thursday October 18, 2018 @04:43PM (#18251944)
But you still use the OOP concept of inheritance, which is basically "indirect methods with function pointers". Beside, "interfaces" don't even exist as a syntaxic concept in many OOP languages, C++ being the most prominent one.
Re:OOP Is Dead, Long Live OOP by munchbunny on Thursday October 18, 2018 @06:51PM (#18252907)
That's splitting hairs. Regardless of the syntax mechanism used to achieve it, inheritance of interfaces and inheritance of implementation are qualitatively different, in the sense that you can usually tell the difference regardless of language.

Also, C++ has abstract classes with only pure virtual functions, which accomplish the same thing.

Re:OOP Is Dead, Long Live OOP by spdionis on Thursday October 18, 2018 @06:32PM (#18252782)
I think C++ is the only one that doesn't have interfaces.
Re:OOP Is Dead, Long Live OOP by maxxxxx on Thursday October 18, 2018 @08:07PM (#18253395)
An abstract class with only abstract methods is essentially the same.
Re:OOP Is Dead, Long Live OOP by jcelerier on Friday October 19, 2018 @07:57AM (#18256032)
It's most certainly not:

- you have to at least implement the destructor if you are going to use the abstract class across multiple DLLs - else, dynamic_cast won't work since each DLL may have its own type_info object for the abstract class

- even if a method is marked abstract, it can still have a default implementation: https://gcc.godbolt.org/z/bAE7v6 though other prominent OO languages are slowly catching up with this ;)

Re:OOP Is Dead, Long Live OOP by spdionis on Thursday October 18, 2018 @06:32PM (#18252776)
extends != implements
Re:OOP Is Dead, Long Live OOP by kazinator on Thursday October 18, 2018 @03:20PM (#18251313)
Inheritance can be so randomly abused as just a code saving hack.

Look how I abused inheritance in this assembler (for a Lisp virtual machine):

http://www.kylheku.com/cgit/txr/tree/share/txr/stdlib/asm.tl

The object system is used to define opcodes. Methods on these objects (which get instantiated as singletons) then handle assembling and disassembling.

There is a macro defopcode-derived which defines an opcode similar to another one, using inheritance.

There is no reason for the relationship to go one way or the other; it's just "this thing is like that thing, except for this slight difference". The inheritance could basically go in either direction.

Note that defopcode-derived doesn't even have provision in its syntax to specify behavior; the code is 100% re-used. The only thing different about the derived opcode is the instruction mnemonic and the opcode bits. Inheritance is used just to override a number and symbol which are static slots.

Re:OOP Is Dead, Long Live OOP by cloudkj on Thursday October 18, 2018 @06:16PM (#18252644)
Inheritance indeed can be pinpointed as the one major problem in problematic OO code. A lot of the comments here talk about abuse and I think that hits it on the head. It’s not really a matter of knowing when to use or not use inheritance, but rather that the developers that do use it end up using it everywhere and a bad pattern proliferates into even more problematic areas, such as using inheritance for mock objects in unit tests.
Re:OOP Is Dead, Long Live OOP by noblethrasher on Thursday October 18, 2018 @03:51PM (#18251549)
Or… if you're talking about languages like C# and Java (and presumably C++), just make sure all of your classes are either sealed or abstract. This turns classes into proper algebraic data types.

To wit, implementation inheritance gives you a sum type (e.g. a Shape is either a Circle, or a Square, or…) whereas interface inheritance gives you a product type (class Foo : IBar, IBaz means that Foo is an IBar and an IBaz).

Re:OOP Is Dead, Long Live OOP by confusius on Monday October 22, 2018 @04:36AM (#18273067)
"languages like C# and Java" Not particularly your post, because compared to e.g Haskell you could say that, but I usually cringe when people say "C# and Java", and often list a hsot of bad attributes that are more particular to Java. Java is such an utterly verbose, dull, ugly, clumsy to use language that falls over its own feet all the time, expecially when adding new features that are at best half as useful as they could be because of early design problems... Whereas C# is, comparably, such a joy to use... ;)
Re:OOP Is Dead, Long Live OOP by rienbdj on Friday October 19, 2018 @11:54AM (#18257607)
Nice idea, but without match expressions (checked by the compiler) it’s just not as good as a true FP language.
Re:OOP Is Dead, Long Live OOP by bendavis381 on Thursday October 18, 2018 @04:13PM (#18251721)
And don’t use a class if it holds no state.
Re:OOP Is Dead, Long Live OOP by Ace17 on Friday October 19, 2018 @01:29AM (#18254417)
This is not so simple. What about "NullLogSink" and "StdoutLogSink", both being implementations of "ILogSink"?

Classes are very well suited to statically formalize the communication points (aka "interfaces", "protocols") between the various parts of your program.

The fact that a concrete class might have a state is actually irrelevant (indeed, we generally make all of our data members "private").

Re:OOP Is Dead, Long Live OOP by pjmlp on Thursday October 18, 2018 @02:05PM (#18250605)
We made it optional in many languages, the problem is how it many people teach OOP, and how it gets abused.
Re:OOP Is Dead, Long Live OOP by blindwatchmaker on Thursday October 18, 2018 @07:41PM (#18253282)
Mutable internal state is problematic with or without inheritance.
Re:OOP Is Dead, Long Live OOP by maxxxxx on Thursday October 18, 2018 @07:58PM (#18253363)
There are plenty of use cases where you need internal state. Think about UI in a desktop app for example. Not everything is a data pipeline with a clear in and out.
Re:OOP Is Dead, Long Live OOP by mercer on Sunday October 21, 2018 @06:50AM (#18267464)
Considering the popularity of React/Redux, it does seem like avoiding internal, mutable state as much as possible and approaching as much of the rest as possible as a 'data pipeline' is a very valid way of dealing with UI's.