From: Robert Klemme Date: 2011-04-08T00:11:47+09:00 Subject: Re: Hash Surprises with Fixnum, #hash, and #eql? On Thu, Apr 7, 2011 at 4:49 PM, Phillip Gawlowski wrote: > On Thu, Apr 7, 2011 at 4:28 PM, Robert Klemme > wrote: >> >> Well, even with technical inheritance ("kind of") sub often add state >> (i.e. member variables) but do only restrict valid values of >> superclass state if at all.  The cannot do otherwise because then >> superclass methods may break.  Silly example: superclass holds an >> index which must be >= 0.  All superclass methods use that index for >> some kind of lookup.  Assuming a sub class would suddenly set that >> value to -13 the superclass contract would be violated.  Now, if you >> let Complex inherit from Real (trying to avoid "irrational" :-)) you >> would add another field for imaginary part.  So far so good, but >> method to_f would sometimes throw an exception in Complex which it >> would never do in Real.  So suddenly Complex breaks Real's contract. > > But that's a failure of implementation, isn't it? That too, but the root cause lies in the area of the incompatibility of the design with the properties of numerical classes. > If I were to implement my own class Complex, I'd have to deal with the > edge-cases that my sub-class has and can produce. > > Thus, I either undefine #to_f, or redefine it so that it throws an > Exception. the value of inheritance is, after all, generalization, so > that I don't have to reimplement the wheel all the time, instead > making the wheel bigger or smaller, as the implementation requires. > That conversely also means that that more specialized sub-classes > derived from a generic-er super-class, *has* to implement an interface > that works, and works consistently. > > To stay with Complex as an example: > #to_f would require an additional argument to work properly: Either > convert the real, or the imaginary part into a Float, and so would > anything derived from Complex, whatever that may be, if it has the > same properties. But we were talking about the case of Complex inheriting Float. Your arguments do not make sense with a Float class because there is no imaginary part yet you would need them in order to be able to provide a meaningful to_f in the subclass Complex. >> That's why I prefer to look at inheritance as "is a" relationship: >> after all OO is about better abstraction capabilities and to be able >> to hide implementation details behind a clearly defined clean >> interface.  If you let yourself get dragged too much into technical >> issues chances are that the design comes out awful.  Only languages >> which allow to inherit without publishing all features of the >> inherited class (private inheritance e.g. in Eiffel) do not >> necessarily suffer from these issues.  But then, inheritance is just >> an implementation detail in such cases. > > But isn't it always? If you treat it as such it is. However then you using a powerful feature for abstraction and modeling. > Regarding technical issues: Design is a bit of an art; knowing when to > stop abstracting is important. ;) In my experience far too many people in our profession have the other problem: they dive into details too fast and do not think on an abstract level. That's the reason why so much code I get to see has issues. And since design flaws are generally much more costly to repair than mere technical issues I'd rather say people should learn to _start_ abstracting. :-) Thank you for the interesting discussion! Cheers robert PS: I just read that there was another earthquake in Japan and there is a tsunami warning. I hope the best for everybody in that area and I hope these catastrophes end rather sooner than later. -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/