From: ulf on 10 Aug 2006 07:31 Hi everybody, I don't consider myself an expert on the delegation side of the subject, but among all the issues raised in this thread, let me add my $0.03 worth to one particular Q about inheritance aka. subclassing: Rick Elbers wrote: > Op 7 Aug 2006 09:15:21 -0700 schreef "Thomas Kowalski" <th-ko(a)gmx.de>: .... >> >> First attempt to reduce the codelength of the classes contour was to >> >>> subclass it, resulting in a class like DividableContour. > >> Are there contours that are not ? > >> No, there is just one typ of contour used throughout the whole >> software. >> The hierarchy would be something like: >> contour extends dividablePolygon extends closedPolygon > > We are not on the same wavelength. My question is not if its in the > code or software . My question was: are there, in your view, contours > that are not dividable ? Thomas, I am a bit confused: First you talk of DividableContour --[> Contour then of Contour --[> **Dividable**Polygon --[> ClosedPolygon In the following I will talk of the class hierarchy (I) DividableContour --[> Contour --[> ClosedPolygon This is obviously a CORRECT hierarchy, since all dividable contours are contours, and all contours are closed polygons. Reason #1 for this to be a GOOD hierarchy would be the presence of a second subclass in your domain/system: UndividableContour --[> Contour But this is not a necessary reason. Contour is a valid abstraction in its own right, an abstraction at a level of generalization where the issue of dividability is not yet decided. The absence of the divide() method in Contour does not express the negative property that Contour instances CANNOT have a divide() method. Reason #2 for (I) to be a GOOD design would be - as I suspect - that noteworthy parts of the domain/system work with contour-objects (which, as Thomas confirmed, are all dividable contours) but need to know only that these are contours, not whether they are dividable. In particular, most Contour methods would seem to be independent of dividability. (Was your question, Rick, about undividable contours just a Q of pure interest, or did you intend to use the answer for an argument?) Finally, I see Thomas' original concern also as a valid reason #3 for (I) to be GOOD: In modeling a domain, also pragmatic issues play a role. For example, the elements of the class model should better not be too complex to understand them in one chunk. Hence it seems justified to separate the complex property of contours' dividability - or rather the complex behavior of a contour dividing itself along a graph (did I get this right?) - into a specialized subclass. Now, all this of course does not say whether replacing inheritance by delegation would lead to a BETTER structure. For the Q at hand, that would mean that DividableContour does not inherit from Contour but lets its instances delegate Contour-messages to a particular Contour object. - Sorry, but I fail to see the advantage of that. But then again, I'm no expert in delegation. Regards, Ulf Schünemann
From: Dmitry A. Kazakov on 10 Aug 2006 09:52 On 10 Aug 2006 02:26:27 -0700, Thomas Kowalski wrote: > Hi Dmitry, Steven, > > maybe I didn't understood exactly what your discussion is about, but > IMHO the word inheritance is not choosen well. The paradigma > inheritance describes the s/w industrie is simply specialization. Not necessary. Inheritance is just a way to define a relationship between two types. Specialization is a specific property of that relationship. Generalization is another. But the most common case is neither specialization nor generalization. > Every time we define an objects we are adding constraints. Each > methode, each member constraints this class to an actually usable > "item". Since we say an square is a special rectangle, it would be > perfectly fine too have it "inheriting" is this direction, as you > stated already. For in-methods, yes. But out- and inout-methods will be broken. Results are outs. In fact, you can inherit rectangle from square or square from rectangle, that changes little. > The Idea of breaking the "contract" with is implied by the constraints > made by a certain class might be a neat feature in some situations, but > is most of the time not neccessary and would just complicate the whole > typesystem. The problem is that you cannot get a new type without breaking something. A thing exposing same behavior is just the same thing. It walks like a duck it quacks like a duck, it is a duck. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: H. S. Lahman on 10 Aug 2006 10:04 Responding to Kazakov... >>>>In a classic recent example here >>>>the debate centered around deriving Rectangle behaviors from Square >>>>behaviors. The real problem was that Square was defined with a >>>>sideLength knowledge attribute while Rectangle was defined with >>>>majorSideLength and minorSideLength -- apples & oranges. >>> >>>It is not apples and oranges. It is squares and rectangles. (:-)) >>> >>>SideLength is a direct reflection of a trivial geometrical fact (theorem) >>>about squares. This theorem does not hold for rectangles. End of story. >> >>Not necessarily. The geometrical facts are: (A) both have four sides; >>(B) for a square all sides are of the same length; and (C) for a >>rectangle opposing sides are the same length but adjacent sides are not. >> So if one defined sideLengthN (N = 1..4) for Square, then Rectangle >>could be a subclass without any LSP inconsistency in the knowledge >>attributes. > > > But that wouldn't be a definition of square. Because geometrical squares > form a set of things having all properties of squares, which includes the > property B. Of course, you can say that B isn't essential for the problem > at hand, but then I would wonder if squares aren't either. I think a square having four sides of equal length is <part of> the formal definition of a square. So with respect to defining side length using four sideLengthN (N = 1..4) attributes is a valid abstraction (the equality is enforced in initializing the attributes). Similarly, using one sideLength is a valid abstraction. The difference lies in whether LSP is an issue; if one also needs a definition that is consistent with Rectangle, then only the first abstraction of the geometric properties works. >>Nonetheless I think LSP is quite useful in an OO context because one >>tailors object abstractions to the problem in hand. That allows one to >>use tricks like abstraction and a flexible view of logical >>indivisibility to make many LSP issues in the problem space irrelevant >>to the solution context. IOW, one only has to resolve the LSP issues >>that are relevant to the problem in hand. > > > True, but to me that means a defeat of LSP as a principle. It was > introduced solely to ensure substitutability. When you say OK, we have to > check for substitutability in each given case (context), then you merely > return back to the beginning. I see the issue differently. LSP requires that one define what substitutability means in the current problem context and then construct the classes, interfaces, and client contracts around that definition. The real problem here is that current 3GLs do not document what such definitions are. If those definitions are not documented elsewhere, then future maintainers do have to check every context when making a change. If those changes are documented, then the maintainer only needs to check client contexts if the change modifies the original definition of substitutability ************* There is nothing wrong with me that could not be cured by a capful of Drano. H. S. Lahman hsl(a)pathfindermda.com Pathfinder Solutions http://www.pathfindermda.com blog: http://pathfinderpeople.blogs.com/hslahman "Model-Based Translation: The Next Step in Agile Development". Email info(a)pathfindermda.com for your copy. Pathfinder is hiring: http://www.pathfindermda.com/about_us/careers_pos3.php. (888)OOA-PATH
From: S Perryman on 11 Aug 2006 03:52 "Thomas Kowalski" <th-ko(a)gmx.de> wrote in message news:1155201987.219606.310760(a)m79g2000cwm.googlegroups.com... > Hi Dmitry, Steven, > maybe I didn't understood exactly what your discussion is about, but > IMHO the word inheritance is not choosen well. The paradigma > inheritance describes the s/w industrie is simply specialization. Inheritance is a well-chosen word. A relationship whereby one thing acquires the properties of others. Just like the inheritance of your parents' physical characteristics. Or in the event of their demise , (possibly) acquiring their material belongings. > Every time we define an objects we are adding constraints. Each > methode, each member constraints this class to an actually usable > "item". Since we say an square is a special rectangle, it would be > perfectly fine too have it "inheriting" is this direction, as you > stated already. > The Idea of breaking the "contract" with is implied by the constraints > made by a certain class might be a neat feature in some situations, but > is most of the time not neccessary and would just complicate the whole > typesystem. We are not breaking the contract. We are debating how to define the exceptions to the rule in a succinct manner so that a type system can enforce our intent. Regards, Steven Perryman
From: Dmitry A. Kazakov on 11 Aug 2006 04:45
On Thu, 10 Aug 2006 14:04:51 GMT, H. S. Lahman wrote: > Responding to Kazakov... > >> But that wouldn't be a definition of square. Because geometrical squares >> form a set of things having all properties of squares, which includes the >> property B. Of course, you can say that B isn't essential for the problem >> at hand, but then I would wonder if squares aren't either. > > I think a square having four sides of equal length is <part of> the > formal definition of a square. So with respect to defining side length > using four sideLengthN (N = 1..4) attributes is a valid abstraction (the > equality is enforced in initializing the attributes). Similarly, using > one sideLength is a valid abstraction. Yes, any true proposition about square remains true independently on whether we are aware of other propositions. > The difference lies in whether LSP is an issue; if one also needs a > definition that is consistent with Rectangle, then only the first > abstraction of the geometric properties works. The point is that, surely, you can take any set of propositions about squares, name them abstractions, and find some of them being compatible with rectangles. BUT, there are propositions which actually make squares what they are, like width=height is. One could find small sets of those, from which one could infer all others. This is how mathematicians define their objects. Let name them sufficient sets. Now, each such sufficient set will not be a subset of the set of propositions about rectangles. In other words, you can model squares as IS-A rectangles, but they won't be much square... >>>Nonetheless I think LSP is quite useful in an OO context because one >>>tailors object abstractions to the problem in hand. That allows one to >>>use tricks like abstraction and a flexible view of logical >>>indivisibility to make many LSP issues in the problem space irrelevant >>>to the solution context. IOW, one only has to resolve the LSP issues >>>that are relevant to the problem in hand. >> >> True, but to me that means a defeat of LSP as a principle. It was >> introduced solely to ensure substitutability. When you say OK, we have to >> check for substitutability in each given case (context), then you merely >> return back to the beginning. > > I see the issue differently. LSP requires that one define what > substitutability means in the current problem context and then construct > the classes, interfaces, and client contracts around that definition. I agree with that, but I see no contradiction. > The real problem here is that current 3GLs do not document what such > definitions are. If those definitions are not documented elsewhere, > then future maintainers do have to check every context when making a > change. If those changes are documented, then the maintainer only needs > to check client contexts if the change modifies the original definition > of substitutability Again agree. That were a pragmatic solution I liked to have much. But in my eyes it still kills LSP subtyping idea. You say, look, let at the declaration point subtype be anything you wish. Most of the questions about substitutability are postponed until instantiation, when the context will be known. As long as that happens no later compile time, I don't worry. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |