From: topmind on 16 Jun 2005 20:28 > > > >> >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. > > Again, I disagree. Indeed, the two are often implemented with the > exact same structure: a jump table. Polymorphism is simply > indirection with an inverse dependency (i.e. the switch does not know > about the cases, but the cases know about the switch) whereas a > switch/case statement is indirection with a forward dependency. > Well, I won't speak for all possible changes here, but case statements appear to handle removal of mutual exclusitivity more easily. For example, if a person's bank account by decree can now be both checking and savings: // *** BEFORE *** sub calcFees(account) { // pass in a record set fees = 0 select on account.accountType { case "checking" {fees = foo * checkCount} case "savings" {fees = bar * amt} } .... return fees } // *** AFTER *** sub calcFees(account) { fees = 0 // init if (account.hasChecking) {fees += foo * checkCount} if (account.hasSavings) {fees += bar * amt} .... return fees } A polymorphic approach would be a lot more rework and shuffling. > > > ----- > Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com -T-
From: topmind on 16 Jun 2005 20:36 Robert C. Martin wrote: > On 15 Jun 2005 15:56:32 -0700, "topmind" <topmind(a)technologist.com> > wrote: > > > TREES ARE A CRUTCH > > Trees are a red herring. They aren't the issue. There was a time in > the late '80s when OO enthusiasts were very hopeful about inheritance > hierarchies. That feeling passed in the early '90s. The last nail > was driven into it's coffin by the Design Patterns book. > But as I mentioned and described, non-tree OO is really messy. It is like Goto's reborn. Instead of behavioral pointers (gotos), it has structural pointers. And, see how ugly the Visitor pattern is? Even some GOF (pattern) fans are otherwise embarrassed by it. Visitor is two trees caught in a Trek transporter convergence accident. > > ----- > Robert C. Martin (Uncle Bob) | email: unclebob(a)objectmentor.com -T-
From: topmind on 17 Jun 2005 01:22 Robert C. Martin wrote: > On 14 Jun 2005 21:26:30 -0700, "topmind" <topmind(a)technologist.com> > wrote: > > >> Classification hiearchies don't need to be used to model everything in > >> OO. Your argument in this case is very weak. > > > >Yes, but OOP is ugly when you diverge from trees, as described in a > >nearby reply. It loses its "innocence" and becomes messier than the > >alternatives when you go beyond trees in OOP. > > OO *can* become messy, just as procedural can become messy. Both can go low, but OO cannot go high. (Procedural is limited too, but that is why Yin has a Yang: databases.) > But OO > does not necessarily become messy. Mess is something that developers > are there to avoid. The main reason OO is messy is because it does not separate meaning from presentation: http://www.c2.com/cgi/wiki?SeparateMeaningFromPresentation Its "models" are hard-wired into relatively static code. It does not bend to one's desired views. I want to be able query the structure of information and relationships to see and edit it how *I* want it, not how the original coder wanted. I don't give a flying sh8t about *their* favorite views. If you can separate meaning from presentation, then one can custom tune the info for one's own head. It allows one to be selfish and picky. Programming is in the mind, and every mind is different. SMFP allows us to have our cake and eat it too. Further, OO's structures are inharently navigational, and I just find relational leads to better organization in the form of more consistency and more math-like reasoning that can be done with it. Navigational structures are the Goto's of structures and organization: okay for small scale, ugly at a larger scale. OO is supposed to be about *big* systems, but has not learned the lessons of large-scale information management that relational has. -T- oop.ismad.com
From: Miguel Oliveira e Silva on 17 Jun 2005 10:12 "Robert C. Martin" wrote: > On Wed, 15 Jun 2005 19:52:11 +0100, Miguel Oliveira e Silva > <mos(a)det.ua.pt> wrote: > > >"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? > > By adding a new function to a hierarchy, and realizing that certain > derivatives can live with the defaults in the base class. If the inheritance hierarchy is correctly built, then there is no need to verify if certain descendant classes "can live with it". Unlike the procedural alternative, there is no coincidence here: the class's ADT *ensure* a working implementation to (correct) descendant classes. > Indeed, we > add a do-nothing 'rotate' method to the Shape hierarchy, and purposely > allow the Circle class to inherit it. Unless you have a class abstracting a rotating invariant shape (from which circles could inherit), it makes no sense to define a "do-nothing" rotate in a base class (as such). A "rotate" method which does nothing, should only be included in a class whose ADT ensure such behavior. > Same decision made, same knowledge needed to make it. Not at all. > >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. > > I agree. By the same token in a procedural environment, if a data > structure has sufficient data elements, it need not know what new > functions may be written against it. I don't understand your point (sorry). To verify the perfect balanced duality, we should be comparing how OO languages handles the problem of adding new methods to existing classes; to the procedural solution of adding new data types to existing procedures (or functions) [*]. In the first case - thanks to subtyping and subclassing - OOP in general requires only the inclusion of the method implementation in the ancestor classes with enough (ADT) information to implement them. No similar thing (to my knowledge) exists in imperative procedural languages (such as C, Pascal, etc.) for the last case (hence the unbalanced duality). [*] The other reverse dual problem would be to compare solutions of adding new classes in OO, to add new procedures/functions to procedural programming; but that's where both approaches handles extendibility more easily. > *That* is the power of the procedural abstraction. Procedural abstraction is much (much) more limited than ADT (they are *not* duals). ADT require and use procedural and functional abstractions. The problem is that - in general - a procedure (in imperative procedural languages) can only do useful things knowing exactly the internal representation of the data structures required to implement its abstraction (they are tightly coupled with data types). Hence, to maintain its external procedural abstraction, the same procedure is required to have different code for different data types even if those data type are related with each other. > ----- > 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 -- Miguel Oliveira e Silva mos at det.ua.pt - http://www.ieeta.pt/~mos DET-IEETA, Universidade de Aveiro, PORTUGAL
From: Robert C. Martin on 17 Jun 2005 12:18
On 16 Jun 2005 17:28:53 -0700, "topmind" <topmind(a)technologist.com> wrote: >Well, I won't speak for all possible changes here, but case statements >appear to handle removal of mutual exclusitivity more easily. For >example, if a person's bank account by decree can now be both checking >and savings: > >// *** BEFORE *** >sub calcFees(account) { // pass in a record set > fees = 0 > select on account.accountType { > case "checking" {fees = foo * checkCount} > case "savings" {fees = bar * amt} > } > .... > return fees >} > >// *** AFTER *** >sub calcFees(account) { > fees = 0 // init > if (account.hasChecking) {fees += foo * checkCount} > if (account.hasSavings) {fees += bar * amt} > .... > return fees >} > > >A polymorphic approach would be a lot more rework and shuffling. Why do you think so? public class CheckingSavingsAccount implements Account { SavingsAccount sa; CheckingAccount ca; ... decimal calcFees() { return sa.calcFees() + ca.calcFees(); } Since I haven't changed either the code for SavingAccount, nor the code for CheckingAccount, I can still have both, and *also* have a CheckingSavingsAccount. To say this another way, I have added the requirement for combining the two accounts, without changing the existing code. ----- 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 |