From: topmind on


> >
> >> >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


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
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
"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
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
First  |  Prev  |  Next  |  Last
Pages: 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
Next: Use Case Point Estimation