6 ms·
> Is this another ad for big design upfront, aka waterfall? Not at all. You won't even know what the right abstractions are upfront. If you want to express the
by icambron 13y ago
> Is this another ad for big design upfront, aka waterfall?
Not at all. You won't even know what the right abstractions are upfront. If you want to express the point here in terms of coding process, it's something like "refactor your code into this". That the design emerges iteratively isn't the same thing as saying there's no design. Contrast to evolution, which is not just iterative but also has no design at all. No one gets to sit around and think, "huh, let's reorganize this". Because if they did, maybe organisms in convergent evolution would share code.
Edit, let me try that point again, because I don't think that was very clear. You may design iteratively, but you're still designing. "Oh, these things have x in common, so let me build an abstraction that captures that commonality and have them use it." But evolution can't do that. The only design tool it has is mutating existing code into additional subclasses. You have more tools than that, so as a metaphor evolution's "designs" can be described by simpler ontologies. So why limit yourself to those ontologies? You can think of evolution as having ridiculous limitations on the kind of design work it's capable of, which are independent of the fact that it's iterative.
> Strapping bird wings onto a rat often isn't going to work.
That you have to implement genuinely different things differently is true enough, but not really challenging the point that class hierarchies make encapsulation harder. Also: maybe an engineer would design a bat a bit differently inside so that it could use the avian wing tech? Just a thought.
> Why not classify all of our code at the finest grain we can?
My point there was that if you had choose one axis on which to classify parts of your code, implementation details wouldn't likely be it. That you have to choose is a consequence of the strict single-inheritance model here. Completely classifying a software abstraction is identifying the point n-dimensional space that describes it in terms of all the different ways to categorize it. A fool's errand in general, I suspect, but at any rate not possible under the class inheritance model (single or multiple).
Edits: multiple for clarity
- seanmcdirmid 13y ago> Edit, let me try that point again, because I don't think that was very clear. You may design iteratively, but you're still designing. ... You have more tools than that, so as a metaphor evolution as a designer can be described by a simpler ontology. I would claim that our process of building things very much follows the process of evolution even if we have the ability to design explicitly rather than perform random mutations follows by natural selection. Our ability to classify things and carry over implementation fits with this way of building. OOP is not just a way of implementing a design, I would say this is actually secondary: its a way of coming up with a design in the first place where you really don't have it all down in your head before you start coding. This is what so annoys me about Haskell: it works very well when you can figure out everything before hand; in fact, you are expected to think long and hard about your problems because its language abstractions are very unforgiving otherwise. Haskell designs are then elegant out of necessity, and this is very limiting when you just need to get something done (aka worse is better). OO implementations are typically over-engineered and less elegant, not because OO thinking is somehow defective, but because elegance is not required to encapsulate complexity and just get something working. > My point there was that if you had choose one axis on which to classify parts of your code, implementation details wouldn't likely be it. A fool's errand in general, I suspect, but at any rate not possible under the class inheritance model (single or multiple). Implementation details provide the strongest signals of similarity than artificial interfaces. If you were going to let a DNN or RNN classify your code, it would probably be along this axis as well as with how the code was actually used. > That you have to choose is a consequence of the strict single-inheritance model here. I rarely let myself be constrained by single inheritance, even when I'm coding in C# I have my mixin patterns handy (ya, more boilerplate, but I can type fast; all my own languages support mixins). > Completely classifying a software abstraction is identifying the point n-dimensional space that describes it in terms of all the different ways to categorize it. I agree, but if we aren't limited by single inheritance (say linearized multiple inheritance via mixins...or gasp...aspects), then this argument no longer holds.
- icambron 13y agoI'm not an absolutist on any of this either, and in practice I make classes inherit each other when it's convenient and makes my code work well. And it sounds like we agree that using mixins is a powerful way of avoiding the ontology traps that lurk in class inheritance structures, and that not having them is painful and limiting [1]. So I'm not even sure there's a real disagreement here. [1] I too used mixins in C#. Not sure how you'd do it now, but at the time you had to use Castle DynamicProxy and it was...unpleasant. But worth it.
- seanmcdirmid 13y agoFair enough. I just compose my mixins directly and bridge the gap through delegation. I wish these rants included the obvious solutions, I'm really tired of the argument of OOP sucks because...Java. Or OOP sucks because...single inheritance. There are plenty of things we can do to make our languages not suck, and this is not a fundamental limitation of OOP. Upvotes for an intelligent debate.
- moron4hire 13y agoIn C#, you define an interface, and in the same namespace as the interface, you define a set of extension methods to the interface. Any class that implements the interface gets the extension methods. The interface can even be empty. namespace Yarp{ public interface IMixinFoo{ } public static class IMixinFooExt{ public static void DoBar(this IMixinFoo _this){ Console.WriteLine("poo"); } } } namespace Grog{ using Yarp; class Baz : IMixinFoo{ public static void Main(string[] args){ Grog g = new Grog(); g.DoBar(); g = null; g.DoBar(); // still works, if DoBar guards against a null-ref exception } } }
- icambron 13y agoAh, yeah, I'd forgotten about extension methods and how they could be used as mixins. I did indeed switch to that when C# 3 came out. I guess I was just remembering earlier pain.