From: Robert C. Martin on 15 Jun 2005 14:27 On 14 Jun 2005 19:44:19 -0700, "topmind" <topmind(a)technologist.com> wrote: >I am having difficulty finding coherent requirements or code samples >for a dosage system. How about we focus on stuff that polymorphs in >that example. What are the polymorphic types or classes? The requirements are reasonably well stated in overview form in the first article. By the second or third article there is a very concrete requirement specified in detail as an acceptance test. If you follow the example through the columns, you'll find a number of polymorphic entities. Perhaps the first you'll find are the test cases themselves. They derive from the JUnit framework. Next, you'll find that the acceptance test fixtures are based on a polymorphic framework (FIT). Within the application you find a polymorphic gateway to the database, and (Manufacturing) which is a mock object that masquerades as another system. You find that the messages show hints of polymorphism, and may become fully fledged polymorphic entities in a later iteration. Bit by bit, as the application evolves, more and more polymorphism creeps in. The application does not start with a lot of polymorphism. Rather, polymorphism gets added over time in order to keep the application flexible and decoupled. ----- Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com Object Mentor Inc. | blog: www.butunclebob.com The Agile Transition Experts | web: www.objectmentor.com 800-338-6716 "The aim of science is not to open the door to infinite wisdom, but to set a limit to infinite error." -- Bertolt Brecht, Life of Galileo
From: Robert C. Martin on 15 Jun 2005 14:34 On Tue, 14 Jun 2005 17:33:59 -0400, CTips <ctips(a)bestweb.net> wrote: >Contrast this to the implementation using a big-old-switch (of switches) >statement. Each shape will have a tag to control the switch() statement. >This tag will (probably) be an enumerated type. It is relatively >straightfoward for: >- the user to determine all the pairs that are required >- the compiler to spit out a waring regarding an unimplemented pair I quite agree that there are issues. And for some problems switch cases are a better solution than polymorphism. However, OO developers don't melt-down when faced with dual-dispatch problems. In any case, whether the intersection problem is solved by switch, or by visitor, the issue is the same. When a new shape gets added, an intersection method must be written for each other shape that currently exists. Compilers *might* help in either case. In the switch case, you must add to the enumerated type in order to get the switch statements to complain (if you have a language that complains). In the visitor case, you have to add an abstract method to the visitor base class, which will cause the compiler to complain if any of the visitor derivatives don't implement that method. Same difference. ----- Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com Object Mentor Inc. | blog: www.butunclebob.com The Agile Transition Experts | web: www.objectmentor.com 800-338-6716 "The aim of science is not to open the door to infinite wisdom, but to set a limit to infinite error." -- Bertolt Brecht, Life of Galileo
From: topmind on 15 Jun 2005 14:48 > >I agree there is a trade-off, but my observation is that change favors > >case statements most of the time. > > That's where we disagree. I think change favors neither approach, and > that any approach that favors one technique over the other is > necessarily imbalanced. Well, case/if statements are a slightly lower level of abstraction than polymorphism. This also means they can be more flexible. Higher abstraction is great when changes fit that abstraction, but worse off if they don't. I am sure you've encountered situations where you purchase a high-level tool to do a job, but found it lacked some key feature such that you end up buidling one from scratch to get the needed feature. But I admit I cannot readily show this right now. We would have to collect some change scenarios and run them through the code counting line changes, named unit changes, block changes, etc. -T-
From: topmind on 15 Jun 2005 14:51 Oscar Meyer. I'm liked.
From: Miguel Oliveira e Silva on 15 Jun 2005 14:52
"Robert C. Martin" wrote: > On Tue, 14 Jun 2005 19:01:53 +0100, Miguel Oliveira e Silva > <mos(a)det.ua.pt> wrote: > > >Although both approaches (OO and functional/procedural) are in a > >sense dual (as you correctly mentioned), the duality is not balanced > >at all. An ADT need not to know all of its methods possible > >implementations (it may even not know one!). On the other hand, > >the "switch" alike method approach needs to know most (if not all) > >of the possible data types. > > Consider a function named "rotate()" that has a switch on shapes. > What does this function do for circles? Nothing. Correct. But that decision required the knowledge (on the part of the programmer) of the circle's semantics (hence, even the "rotate" procedure needed to know the new circle's ADT). how would you do that automatically as happens in the OO approach? On the other hand, if a method has enough information to be implemented in a given class, it need not to know what will be its possible future descendant classes (as long as those unknown new classes respect that class's ADT semantics and method invocation is dynamically binded, this implementation can be automatically inherited and reused by all of them). This is the power of OO data type abstraction. > There are times when adding a new data structure to a switch > architecture has no impact. There are times when adding a data > structure to an OO architecture has no impact. I think you'd be hard > pressed to prove that the duality is not balanced. (Ok, let me try again.) As said in the other message, there is a very important difference between both approaches which make them unbalanced: the existence of subtyping/subclassing in OO languages. In the OO approach a new class may not be build from scratch, it can and should reuse existing classes (as long as it is able to respect those classes's ADTs). Hence, it needs "only" to implement its differences to those existing (inherited) types. On the other hand, a procedural "switch" approach without a subtyping mechanism between data types (I would mostly exclude from this comparison the type structural equivalence present in some functional languages), is required to know all of the semantics of new data types, hence inhibiting the automatic correct reuse of existing procedural code. That existing procedural code may sometimes work in new data types, but there is no way of knowing (and depend on) that in advance giving it poor modularity properties (in particular: modular continuity). A more balanced dual approach to OO programming, would be a functional approach with structural type equivalence, allowing the construction of functional code which work for structural equivalent data types. So the "thing" that makes both (dual) approaches unbalanced is the type/class relations which are part of OO programming (no such dual "thing" exists in procedural "switch" code). All this being said, the main reason that led me to participate in this thread was my disagreement to one of your points: You wrote: "However, with OO, adding new functions to existing data structures is hard. You have to find every subclass and add a new method." As showed, this is not (often) true. Best regards, -miguel > ----- > Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com > Object Mentor Inc. | blog: www.butunclebob.com > The Agile Transition Experts | web: www.objectmentor.com > 800-338-6716 > > "The aim of science is not to open the door to infinite wisdom, > but to set a limit to infinite error." > > -- Bertolt Brecht, Life of Galileo -- Miguel Oliveira e Silva mos at det.ua.pt - http://www.ieeta.pt/~mos DET-IEETA, Universidade de Aveiro, PORTUGAL |