I love that inheritance lets me customize 3rd party code and integrate with it smoothly; nothing pisses me off more than a "sealed" class that you can't inherit from.
I love that inheritance lets me customize 3rd party code and integrate with it smoothly; nothing pisses me off more than a "sealed" class that you can't inherit from.
"Smoothly". For my 8 years with Java the only base classes that haven't been retroactively modified and thus breaking my inherited classes... were the ones in the stdlib. Everything else could and has been pulled under my feet, many times.
Everyone and their moms and dogs was like "hey, I think I can do better because I feel great this week!" and then 10 of us had to repair an object hierarchy of 200+ classes. I mean, everybody knows the CTO can't make a mistake, right?
And don't give me the "not in a disciplined team!" argument. Even disciplined teams make mistakes because often the author has no idea how many other colleagues use their base class.
I know the idea sounds too good to ever believe that it can't be true -- but yeah, it's not true.
> nothing pisses me off more than a "sealed" class that you can't inherit from
The "sealed" classes are meant to be semantic boundaries. Get an instance of it in your object and be done with it. What's so triggering about that?
> The "sealed" classes are meant to be semantic boundaries.
The author of the "sealed" class definitely imagined all possible use cases and their code has absolutely no bugs, right?
...What?
You can compose an instance of the sealed class in yours. You lose all brittleness from inheritance in the process. I've been coding OOP most of my life and I am working with FP for 2 years now -- composition never introduced a bug. Sure it's anecdotal but after a trend repeats itself 5+ times, you start observing patterns and making conclusions.
Additionally, a number of FP languages offer Java-like and Go-like interfaces for an extra peace of mind.
But I can't subclass a sealed class to fix a bug or add a feature and pass it back into the framework to use. And yes, I have needed to do this otherwise I would never notice it was sealed in the first place.
I'm not sure what this means? In your modernized UI framework, how would you want to be able to make UI tweaks to built in OS/framework components?
I've seen a few other system for customization and they all tended to be worse than just being able to subclass internal classes and override methods. Now I admit this can be terribly brittle but often the alternative is no way to customize at all.
I don’t really see why this would be better, to me the two approaches seem isomorphic...
nsTableView ::
{ renderCell :: a -> NSView -- this is the function that renders a cell given an `a`
, header :: NSView
, footer :: NSView
}
-> [a]
-> NSTableView a
I.e. pass in a function that renders a cell for a given `a`, a header and a footer NSView and whatever else, a list of `a`s and get back a NSTableView which displays that list of `a`s.React calls this pattern higher order components iirc.
1. Overriden methods have access to the internal state of the parent class, which is almost universally a bad idea.
2. Since functions are values, you can freely mix and match different view configurations without having to create a subclass for every permutation.
#2 is a good point. But there are some limitations as well. You don't get to augment the default implementation unless it is also exposed somewhere (passed into the function).
Both methods have a lot in common with the obvious differences that you mention. A class with no public methods and a empty virtual function is equivalent to a class calling a higher order function in the same place. If that virtual function has a implementation, you can get the same functionality with a higher order function by passing in the base implementation as a parameter. For full equivalence, you could also pass the object instance as well. Add in protected methods and/or state and you can get that with a second class that implements an internal API and again pass that to the higher-order function.
Ultimately you can achieve all kinds of equivalence this way. I think there is some advantage to using the terminology in the language (private, protected, virtual, abstract, this/base, etc) to describe the more complex situations. Having a simple function call is useful for more simple situations. This is the classic struggle.