4 ms·
> I admit I would really like a 'delegate function call to <object>' construct Yeah, I'd love to see Kotlin's delegation[0] developed further and appear in oth
by Tmpod 3y ago
> I admit I would really like a 'delegate function call to <object>' construct
Yeah, I'd love to see Kotlin's delegation[0] developed further and appear in other languages as well.
[0]: I admit I would really like a 'delegate function call to <object>' construct
- mike_hearn 3y agoKotlin's delegation feature is useful sometimes, but OOP inheritance still crops up more often. One reason is that inheritance is strictly more powerful. When you delegate (compose), you can't modify the inner working of the object you delegated to, you can only wrap it. Often that's not sufficient. You want to actually customize the implementation in some way. OOP's inheritance is ideal for this, because the superclass can clearly define chunks of functionality that subclasses are allowed to either (a) replace entirely or (b) wrap or (c) provide (abstract methods). This is a very flexible approach. With mere delegation you can only wrap, and only for method calls that originate outside the object, and only for public methods. It's also clean. The distinction between what you must implement, what you can implement and what is for the user is defined in the type system and enforced by the compiler. Additionally you separate the interface for customizations from the interface for users (protected vs public), which keeps documentation and auto complete properly focused. When combined with dependency injection and code generation it also allows third party frameworks and libraries to enhance the code you write in various ways, that remain mostly tucked out of the way but can be revealed in an IDE in an instant (and a good IDE will show visual hints that there are such customizations in effect). The final advantage is that in some languages the implementation is highly optimized. On HN you'd be forgiven for thinking nobody writes virtual method calls since 20 years ago but in reality virtual method dispatch is so common in real programs that it's heavily optimized by both CPUs (sophisticated indirect branch caching) and language runtimes (PICs in fast VMs like Hotspot or V8). Composition is less well optimized. Inheritance gets an overly bad rap on Hacker News, despite how prevalent it is. I think this is because it's so flexible you can easily make a mess with it, and some people have. Also the decision of Java to make all classes and methods open by default means overriding is often used as a hacky way to hot-patch libraries in the field, rather than as part of any principled overall design. Kotlin reverses that decision to some extent and so classes and methods are all final by default, unless a compiler plugin overrides that. I also suspect the move to web development has had this effect, because in most classical OOP toolkits you are allowed or even encouraged to extend the UI by subclassing pre-existing node types. So you can make a custom button by subclassing Button or whatever. HTML is implemented using classical OOP designs, but mostly for implementation reasons that isn't exposed to the web developer who instead is expected to customize the controls purely through CSS and setting properties. If you want to make a custom button widget, well that's too bad, better learn React or something similar. So people just aren't exposed to the situations where OOP is useful because browsers weren't designed for UI, and the memory of why it was originally developed atrophies. And some of it is just memeing. OK, now tell me why I'm wrong.
- _a_a_a_ 3y agoI don't have much time so pardon the brevity, but I believe it's been proven that inheritance and delegation have equal expressiveness. > Often [delegation] not sufficient. You want to actually customize the implementation in some way. OOP's inheritance is ideal for this The usual way of customising behaviour without inheritance is to pass in an object to actually implement the behaviour. var LogToConsole = new logger(new WriteToConsole()); vs var LogToFile = new logger(new WriteToFile()); Which customises the logger class. Trivial example but I use this a lot. > I think this is because [inheritance is] so flexible you can easily make a mess with it, and some people have agreed
- mike_hearn 3y agoIt's all Turing complete, so of course you can implement the same thing as protected methods by using callbacks. When I say power here I don't mean in the sense that you literally can't do it any other way, I mean it's more convenient and natural. C++/Java/Kotlin style OOP is basically about putting common design patterns into language syntax. You could do it all with C, but it's easier if the compiler does it for you. For example Kotlin has "data classes" and Java now has "records" which are in both cases classes, but they sacrifice inheritance in order to auto-generate more boilerplate for you. That's still OOP though.
- lmm 3y ago> One reason is that inheritance is strictly more powerful. When you delegate (compose), you can't modify the inner working of the object you delegated to, you can only wrap it. It's more powerful, sure, but in the same way that goto is more powerful than if/for/while. In theory some languages give you the tools for a superclass to expose a stable interface to its subclasses (ish - even Java doesn't give you a way to specify "subclasses may read but not write this field", for example), but in practice they're rarely used (Wicket is literally the only library I've seen to offer an effective inheritance interface); the overwhelming majority of the time inheritance ends in fragile base classes and the resulting bugs. Which is perhaps inevitable; the trouble with giving you the tools to change the superclass's behaviour in unintended ways is that it results in people changing the superclass's behaviour in unintended ways. If you have a locked-down inheritance model where classes and methods are final by default then maybe you avoid the fragility problem - but by the same token if subclasses can only use extension points that were deliberately exposed then you're probably not gaining much flexibility over what you could do with composition. > The final advantage is that in some languages the implementation is highly optimized. On HN you'd be forgiven for thinking nobody writes virtual method calls since 20 years ago but in reality virtual method dispatch is so common in real programs that it's heavily optimized by both CPUs (sophisticated indirect branch caching) and language runtimes (PICs in fast VMs like Hotspot or V8). Composition is less well optimized. Shrug, as the language design consensus shifts, the implementation optimizations will follow. Composition should ultimately be easier to get better performance out of, because it's more constrained (in particular, knowing that a given class or method is final means that you can optimise that class or method much more aggressively). > So people just aren't exposed to the situations where OOP is useful because browsers weren't designed for UI, and the memory of why it was originally developed atrophies. AIUI the association between OOP and GUI is more of a historical coincidence than a deliberate design. Though I agree that they do seem to fit together well.