[Fwd: Case statements, decision trees, and good OO design] 
Author Message
 [Fwd: Case statements, decision trees, and good OO design]


Quote:
> I have developed a class that is more flexible than Case/Switch called
> If. The way to use it is as follows:

...snip...

For further reference and ideas, here is the Switch class from
QKS-Smalltalk/SmallScript -- you're free to use it. It inherits from
<IndexedSlotCollection>, but (depending on dialect) you'll probably want to
make it a subclass of something like <OrderedCollection> which supports
ordered #add: value operations.

    (Switch new)
    case: ... do: [
    ];
    case: [...] do: [
    ];
    default: [
        ...
    ];
    on: switchValue.

Or duplicating the previous posters if/else example:

    res := (Switch new)
    case: 2 do: [1];
    case: 1 do: [2];
    case: 3 do: [3];
    default: [4];
    on: x.

Switch class source follows: (No compiler changes are required but a
compiler can easily optimize this form)
---------------------------
Inherited methods required are:
    #add:, #at:
External messages used are:
    #class, #==, #=, #~=, #+
    #to:by:do:, #ifTrue:ifFalse:, #value:

NOTE: QKS Smalltalk allows blocks (and methods) to be valued with more or
less arguments that they were declared with. So, you may want to replace
references to #value: for the <caseValuable,defaultHandlerValuable> with
#value.
---------------------------
<!--BEGIN Switch-->
<class name   ='Switch;
               {BCF183CE-331B-445E-8721-BDB448B456D9};
               {917D20F6-6BAC-4B14-BDE8-BD71222E18E2}'
  extends     ='IndexedSlotCollection;
               {42524DCD-19C0-4106-8347-D547F3F4CC4A}'
  inst-vars   ='defaultHandler'
  authors     ="David Simmons"
  version     ="1.0.0"

<!--Switch--><?method [
default: defaultHandlerValuable

   "This registers a default statement to be executed when no other
    on: value matches a statement."
    defaultHandler := defaultHandlerValuable.
]?>

<!--Switch--><?method [
case: caseValuable
  do: handlerValuable

   "This registers a statement to be evaluated and then compared to
    the passed value: parameter."
    self add: caseValuable; add: handlerValuable.
]?>

<!--Switch--><?method [
exactlyOn: switchValue

   "This causes the array of conditions to be tested in the defined
    order. The first condition to evaluate to true has its do: block
    evaluated and the result is returned. Test uses #==."
    1 to: self size by: 2 do:
    [:i||case|
        ((case := self at: i) class == Block) ifTrue:
        [
            ((case value: switchValue) == switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ] ifFalse:
        [
            (case == switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ].
    ].
    defaultHandler ? [^nil].
   ^defaultHandler value: switchValue
]?>

<!--Switch--><?method [
equivalentlyOn: switchValue

   "This causes the array of conditions to be tested in the defined
    order. The first condition to evaluate to true has its do: block
    evaluated and the result is returned. Test uses #~=."
    1 to: self size by: 2 do:
    [:i||case|
        ((case := self at: i) class == Block) ifTrue:
        [
            ((case value: switchValue) ~= switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ] ifFalse:
        [
            (case ~= switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ].
    ].
    defaultHandler ? [^nil].
   ^defaultHandler value: switchValue
]?>

<!--Switch--><?method [
on: switchValue

   "This causes the array of conditions to be tested in the defined
    order. The first condition to evaluate to true has its do: block
    evaluated and the result is returned. Test uses #=."
    1 to: self size by: 2 do:
    [:i||case|
        ((case := self at: i) class == Block) ifTrue:
        [
            ((case value: switchValue) = switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ] ifFalse:
        [
            (case = switchValue) ifTrue:
            [
                "Invoke the <handler>"
                ^(self at: i+1) value: switchValue
            ].
        ].
    ].
    defaultHandler ? [^nil].
   ^defaultHandler value: switchValue
]?>

<!--Switch--><?method [
value: switchValue

   "This causes the array of conditions to be tested in the defined
    order. The first condition to evaluate to true has its do: block
    evaluated and the result is returned. Test uses #=."
   ^self on: switchValue
]?>
</class>
<!--END Switch;{BCF183CE-331B-445E-8721-BDB448B456D9}-->

-- Dave Simmons [www.qks.com / www.smallscript.com]
  "Effectively solving a problem begins with how you express it."



Mon, 21 Apr 2003 02:48:08 GMT  
 [Fwd: Case statements, decision trees, and good OO design]

Quote:
> Ummmmmm, I think Kent Beck had a pattern called 'Death to case
statements'.
> IMHO, switch statements are not very good OO practice.

> --tc

Aside from the fact that Kent's ideas or words are not gospel...

There are a lot of design and implementation problems and performance
related issues that are either ignored or possibly not understood in making
such a sweeping thesis as 'Death to case statements'.

It is worth noting that Kent's focus is with using OO languages for creating
Business objects and systems. I would suggest that it does not, in general,
address all the issues or cases for software development across the entire
spectrum.

-- Dave Simmons [www.qks.com / www.smallscript.com]
  "Effectively solving a problem begins with how you express it."

Here are snippets from posts I made on a CLS thread earlier this year.

Thread title was:
   "Re: Major differences between Smalltalk and Java"

************************************
************************************

Quote:

message




> > > >If you feel the need for a case
> > > >statement, it's easy enough to do with a Dictionary.

> > > Yes, you can use this trick, but many times I don't want the extra
> > > overhead of creating a dictionary object and filling up the dictionary
> > > with the blocks, evertime the method is invoked.

> > What kind of alternative do you suggest? I can't think of an alternative
> > where you don't have to pass in all the blocks anyway, something which
I'm
> > guessing that you would still resist for performance reasons.

> > What's your extension, James?
> > --
> > Wayne Johnston

> I'm not James but I thought you'd find it useful to know that QKS
Smalltalk
> has had a standardized inlineable switch form since 1991. I believe The
QKS
> dialect was the first to define switches and it is my understanding that,
> like a variety of other new QKS Smalltalk constructs, this switch
> implementation was also adopted by both Dolphin and Squeak.

> Like cascadable exception guards, the entire expression "(Switch new) and
> its cascaded messages" are always inlineable (and it should be easy for a
> smalltalk compiler to inline them via its parse-tree) for hi-performance
> execution. As with most optimizations for Smalltalk, we designed this
> construct (and a portable <Switch> class) to both compile and execute
> without requiring compiler inline support (it's just a whole lot faster
and
> more efficient to have the compiler inline support).

> (Switch new)
> case: "value or Block" do: [...];
> ...
> default: [...];
> on: value. "#= equality matching of cases"

> (Switch new)
> case: "value or Block" do: [...];
> ...
> default: [...];
> exactlyOn: value. "#== identity matching of cases"

> (Switch new)
> case: "value or Block" do: [...];
> ...
> default: [...];
> equivOn: value. "#~= equivalence matching of cases"
> " or #equivalentlyOn:"

> If the case expression is a block, then it is injected with the switch
> argument as in:
> case: [:switchArg| ...] do: [...]

> The block is then evaluated and the result of the block valuation is
treated
> as the case value for "...on:" testing.
> ----------------------------------
> ----------------------------------
> SIDEBAR: Transforming and maintaining code (and subsequent updates) from
one
> language or associated style to a Smalltalk usage can be problematic.

> In that scenario, it is useful to have constructs to capture and preserve
> the original code's intent...

> I.e., It is also the case that switch statements have the value that they
> provide a locality of reference for the human programmer to understand the
> conditional flow of execution.

> Switches can outperform message sends and have the ability to efficiently
> combine cases without messaging at all. They should not be used for
general
> patterns of behavi{*filter*}dispatching but may be quite appropriate for
> maintaining the simplicity (for purposes of understanding) of a specific
> algorithm (while possibly gaining (as opposed to losing) performance
> benefits).

> In general, it is important to distinguish control flow design based on
> behavior from that based on value. I.e., it is bad form to write
> control-flow code based on something responding to some suite of behavior;
> it is appropriate to write control-flow-code based on specific values of
one
> or more types.

> NOTE: The following snippets are written in SmallScript which has an XML
> source form; within method source the SmallScript annotation operator
> '<...>' is used. SmallScript is a new language that fully incorporates and
> extends the QKS' Smalltalk-2000 dialect.

> "" Bad form -- it is based on behavioral/type intent
> "" Use polymorphism instead
> if (t class == XX)
> ...
> else if (t class == Y)
> ...

> "" Appropriate and more efficient than messaging
> "" since messaging will not discriminate a 'foo'
> "" value from a 'bar' value unless they are of
> "" different types (and even if they were, the
> "" intent was to distinguish the 'foo' value from
> "" the 'bar' value not their behavior types.
> if (t = foo)
> ...
> else if (t = bar)
> ...

> "" Or a SmallScript switch form
> switch (obj)
> [
> case foo: "" Case 'foo' will do both
> action1... "" action1 and action2
> case bar:
> action2...
> break.
> case [... abc ...]: "" a completely dynamic-case
> action3...
> break.
> ].

> Similarly, if/unless/assert can provide similar value.
> --
> if (cond) "" #ifEquivTrue:
> expr
> else if "or 'unless'" (...)
> --
> unless (cond) "" #ifEquivFalse:
> expr
> else if "or 'unless'" (...)
> --
> assert (cond) "" if assert-level-enabled on thread
> expr "" and (cond) ifEquivTrue:
> else ...
> --
> assert:level (cond)
> expr
> ...
> --
> ==============================

> -- Dave S. [www.qks.com]

************************************
************************************

- Show quoted text -

Quote:
> > Similarly, chains of if-then-elseif-then-else or
> > switch statements generally indicate that someone hasn't thought very
> > carefully, as these constructs are usually what polymorphism is for.

> > ---
> > Doug Palmer "I've got that certain nothing,

> > < http://www.*-*-*.com/ ~doug>

> This is only makes sense if everything is already an object and if all
> "data" has a behavi{*filter*}representation. This is a limited and perhaps
> impossible way to view the world.

> Ask yourself:

> Is "1" a different class from "2"?
> Is "'asString'" as different class from "'new'".

> Obviously, the word "class" itself tells us there is a "grouping" and we
> know that implies similar characteristics ("behavior" in OO-terms and
> structure in procedural-terms). However, the members of the group are
> "values" that share the same "behavior".

> So, obviously we need some way to express distinctions between the values
> and sometimes to "marshal" values between one behavi{*filter*}group and
another.
> The need for this and the solutions to addressing that need have nothing
to
> do with "behavior" and thus nothing to do with OO concepts as you're
trying
> to express them.

> Control flow is about the expression of decision making. Not all decisions
> are of a "behavioral" form -- this is the flaw in "pure" OO thinking as it
> leaves no room for all the rest.

> if (aString = 'abc')
> ...body...
> else if (aString = 'def')
> else if (aString = 'xyz')

> if (interest > 0.05 and: [cost < 50])
> else if (interest > 0.08 and: [cost > 200 and: [balance < 4000]])
> ...

> What is behavi{*filter*}about the preceding types of constructs? These
examples,
> while not from any real code, are not atypical of what one encounters in
> general programming problems. This kind of expression of relationships
> between values (or sets of values) is one of the basic elements that forms
> the basis for functional languages. And it is the basic kind of problem
from
> which procedural languages evolved.

> The above two examples take a form that provides "locality of reference"
for
> a human reader. Which means that one can go to one location to understand
> the decision process. Whether they are an appropriate use of control-flow
or
> a misuse in view of behavi{*filter*}constructs depends on what the various
> control flow body statements contain -- one would assume they would be
short
> and succinct often translating the value operation into some behavi{*filter*}
> construct.

> Given one is working in a language that has OO facilities, syntactic
> constructs can be easily misused, just like OO semantics can be easily
> misused for things like value operations. One can take an otherwise
concise
> and clear set of value relationships and completely obscure and obfuscate
> them with extra effort to "objectify" the implementation of the problem
> solution. This is not a black and white issue. It often has to do with the
> granularity/scale of the problem and as a problem evolves it may well need
> to be "refactored" to express the solution using more or less of the
"pure"
> object facilities available.

************************************
************************************

- Show quoted text -

Quote:
> From a design point of view the question of using some form of "if"
> conditionals versus a dispatched behavior mechanism cannot be determined
> without understanding more about the problem itself.

> Under what situation is this better (before answering look at the more
> reasonable approach next):
> ---------------------------------------------------------
> | dispatchTable |
> (dispatchTable := Dictionary new)
> at: 'abc' put: #someSelectorA:with:;
> at: 'def' put: #someSelectorB;
> at: 'xyz' put: #someSelectorC:.
> selector := dispatchTable

...

read more »



Mon, 21 Apr 2003 04:04:24 GMT  
 [Fwd: Case statements, decision trees, and good OO design]
re:  'I would suggest that it does not, in general, address all the
issues or cases for software development across the entire spectrum.'

Of course it doesn't.

I worked in an engineering environment writing software for an
intelligent gripper (for a robot) that had to process real time data.
The project manager made most of the decisions about what language to
use (which was Pascal), environment, etc.  After the system was
implemented, it was found to be too slow.  The PM had us go thru the
code and short circuit loops by doing a break as soon as possible, use
case statements, etc.  The code improved by only a few milliseconds.

What I am saying is, I find it to believe that an ST switch statement
makes the difference between an acceptable software solution and an
unacceptable one.  However, good OO practice is sacrificed by using
them, IMHO.

--tc

Sent via Deja.com http://www.deja.com/
Before you buy.



Mon, 21 Apr 2003 05:14:00 GMT  
 [Fwd: Case statements, decision trees, and good OO design]
Simple fact is that every version of Smalltalk is littered with the
equivalent of case statements.  All you need to do is look for a nested if
statement and you have a pretty good chance of replacing it with a case
statement and making more readable and probably faster.

Chris Lopeman
Object Link Inc.

Quote:

> re:  'I would suggest that it does not, in general, address all the
> issues or cases for software development across the entire spectrum.'

> Of course it doesn't.

> I worked in an engineering environment writing software for an
> intelligent gripper (for a robot) that had to process real time data.
> The project manager made most of the decisions about what language to
> use (which was Pascal), environment, etc.  After the system was
> implemented, it was found to be too slow.  The PM had us go thru the
> code and short circuit loops by doing a break as soon as possible, use
> case statements, etc.  The code improved by only a few milliseconds.

> What I am saying is, I find it to believe that an ST switch statement
> makes the difference between an acceptable software solution and an
> unacceptable one.  However, good OO practice is sacrificed by using
> them, IMHO.

> --tc

> Sent via Deja.com http://www.deja.com/
> Before you buy.



Mon, 21 Apr 2003 05:40:43 GMT  
 [Fwd: Case statements, decision trees, and good OO design]

Quote:
> Simple fact is that every version of Smalltalk is littered with the
> equivalent of case statements.  All you need to do is look for a nested if
> statement and you have a pretty good chance of replacing it with a case
> statement and making more readable and probably faster.

Right. Or. . .
I have a parent object aggregating a collection of children stored
by keys, i.e., using a Dictionary. Very common pattern, is it not :-?
Now I need to send a message to one of the children based on
matching a key.
So, its match the key, find the value and send a message to it.
Uh, that's a case statement.


Mon, 21 Apr 2003 08:38:18 GMT  
 [Fwd: Case statements, decision trees, and good OO design]

No matter how bad it is, people  make their own case/if elseif
classes.  But the bigger problem is that there is no standardized
class that we all can adhere to. And thats the shame of it.  

Costas Menico

Quote:



>> Simple fact is that every version of Smalltalk is littered with the
>> equivalent of case statements.  All you need to do is look for a nested if
>> statement and you have a pretty good chance of replacing it with a case
>> statement and making more readable and probably faster.

>Right. Or. . .
>I have a parent object aggregating a collection of children stored
>by keys, i.e., using a Dictionary. Very common pattern, is it not :-?
>Now I need to send a message to one of the children based on
>matching a key.
>So, its match the key, find the value and send a message to it.
>Uh, that's a case statement.



Mon, 21 Apr 2003 10:30:38 GMT  
 [Fwd: Case statements, decision trees, and good OO design]
What your saying is there is bad code in any language.  I don't
disagree with you.

--tc



Quote:
> Simple fact is that every version of Smalltalk is littered with the
> equivalent of case statements.  All you need to do is look for a
nested if
> statement and you have a pretty good chance of replacing it with a
case
> statement and making more readable and probably faster.

> Chris Lopeman
> Object Link Inc.


> > re:  'I would suggest that it does not, in general, address all the
> > issues or cases for software development across the entire
spectrum.'

> > Of course it doesn't.

> > I worked in an engineering environment writing software for an
> > intelligent gripper (for a robot) that had to process real time
data.
> > The project manager made most of the decisions about what language
to
> > use (which was Pascal), environment, etc.  After the system was
> > implemented, it was found to be too slow.  The PM had us go thru the
> > code and short circuit loops by doing a break as soon as possible,
use
> > case statements, etc.  The code improved by only a few milliseconds.

> > What I am saying is, I find it to believe that an ST switch
statement
> > makes the difference between an acceptable software solution and an
> > unacceptable one.  However, good OO practice is sacrificed by using
> > them, IMHO.

> > --tc

> > Sent via Deja.com http://www.deja.com/
> > Before you buy.

Sent via Deja.com http://www.deja.com/
Before you buy.


Mon, 21 Apr 2003 13:20:19 GMT  
 [Fwd: Case statements, decision trees, and good OO design]
No, that is not what I am saying.  What I am saying is that since most of us
admired Smalltalk (The base system) even to the point of basing our careers
on it,  and it has many occurrences of the type of statement, then that type
of statement cant be all that bad.

To add to this, I have seen far too many object oriented systems that have
created far too many objects to do the job.  Making them nearly impossible
to understand, and delegate responsibility so much that nothing ever
actually gets done.  I will not create a new class or classes to do the job
of a flag.  Nor will I do it to do the job of a nested if statement that is
used by one place; and would have each new class with a single method used
to handle what the case statement can do.

Chris Lopeman
Object Link Inc.

Quote:

> What your saying is there is bad code in any language.  I don't
> disagree with you.

> --tc



> > Simple fact is that every version of Smalltalk is littered with the
> > equivalent of case statements.  All you need to do is look for a
> nested if
> > statement and you have a pretty good chance of replacing it with a
> case
> > statement and making more readable and probably faster.

> > Chris Lopeman
> > Object Link Inc.


> > > re:  'I would suggest that it does not, in general, address all the
> > > issues or cases for software development across the entire
> spectrum.'

> > > Of course it doesn't.

> > > I worked in an engineering environment writing software for an
> > > intelligent gripper (for a robot) that had to process real time
> data.
> > > The project manager made most of the decisions about what language
> to
> > > use (which was Pascal), environment, etc.  After the system was
> > > implemented, it was found to be too slow.  The PM had us go thru the
> > > code and short circuit loops by doing a break as soon as possible,
> use
> > > case statements, etc.  The code improved by only a few milliseconds.

> > > What I am saying is, I find it to believe that an ST switch
> statement
> > > makes the difference between an acceptable software solution and an
> > > unacceptable one.  However, good OO practice is sacrificed by using
> > > them, IMHO.

> > > --tc

> > > Sent via Deja.com http://www.deja.com/
> > > Before you buy.

> Sent via Deja.com http://www.deja.com/
> Before you buy.



Mon, 21 Apr 2003 22:20:54 GMT  
 [Fwd: Case statements, decision trees, and good OO design]

Quote:

>No, that is not what I am saying.  What I am saying is that since most
>of us admired Smalltalk (The base system) even to the point of basing
>our careers on it,

Okay that is pretty clear . . .

Quote:
>and it has many occurrences of the type of statement,

Okay.

Quote:
>then that type of statement cant be all that bad.

Now I am having trouble relating the pieces of the sentence.  I've
known people that have based their careers on Smalltalk and have
written terrible code.  I don't see how one relates to the other tho.
Should someone strive to become better at their chosen career?  My
answer would be yes but not everyone agrees with that and 'strive to be
better' has different meanings to different people.  The result can be
bad code.  Also, sometimes a project has time and budget constraints
and the code suffers.

Quote:
>To add to this, I have seen far too many object oriented systems that
>have created far too many objects to do the job.

You've seen bad code, so have I.

Quote:
>Making them nearly impossible to understand, and delegate
>responsibility so much that nothing ever actually gets done.

Yes, we've both seen bad code.

Quote:
>I will not create a new class or classes to do the job of a flag.  Nor
>will I do it to do the job of a nested if statement that is used by
>one place; and would have each new class with a single method used
>to handle what the case statement can do.

And that is your decision to make.  I don't think we are going to be
able to enumerate all the cases and how to handle them in a forum
message.

Quote:
>Chris Lopeman
>Object Link Inc.

--tc

Sent via Deja.com http://www.deja.com/
Before you buy.



Mon, 21 Apr 2003 23:32:09 GMT  
 [Fwd: Case statements, decision trees, and good OO design]

Quote:
> No, that is not what I am saying.  What I am saying is that since most of
us
> admired Smalltalk (The base system) even to the point of basing our
careers
> on it,  and it has many occurrences of the type of statement, then that
type
> of statement cant be all that bad.

I believe we should minimize case statements and use
polymorphism wherever possible, but:

(1) too much of a good thing makes code hard to read, as stated by Chris

(2) there is a point where it "bottoms out" and if-then-else is required,
i.e,.
case is *required*. I think :-)

We had a discussion about this perhaps a year ago and I'm sure we determined
case statements were necessary at some point. Unfortunately, I'm drawing a
blank on the definitive argument. Perhaps its was just that eliminating them
would require doing self-brain-surgery on the base classes, such as Number.

Interesting subject: Are case statements necessary for even a pure OO
language?



Tue, 22 Apr 2003 08:49:20 GMT  
 [Fwd: Case statements, decision trees, and good OO design]
Case statements are quite useful when parsing external information,
i.e. data from other software or external files.  However, for code
that is completely under control of a smalltalk developer, and information
that is completely internal, I don't know of any reason to use a case
statement.

--
Terry
===========================================================
Terry Raymond       Smalltalk Professional Debug Package
Crafted Smalltalk   *Breakpoints* and *Watchpoints* for
19 Tilley Ave.                  VW and ENVY/Developer
Newport, RI  02840

http://www.craftedsmalltalk.com
===========================================================


Quote:
> We had a discussion about this perhaps a year ago and I'm sure we determined
> case statements were necessary at some point. Unfortunately, I'm drawing a
> blank on the definitive argument. Perhaps its was just that eliminating them
> would require doing self-brain-surgery on the base classes, such as Number.

> Interesting subject: Are case statements necessary for even a pure OO
> language?



Tue, 22 Apr 2003 09:14:56 GMT  
 
 [ 13 post ] 

 Relevant Pages 

1. OO Analysis & Design CASE tool

2. case statement flipflop statement

3. difference if statement with case statement?

4. Decision Day take 2 (fwd)

5. Is anyone aware of APL decision tree software?

6. Looking for a language to express binary decision trees

7. Code to Show Decision trees?

8. decision trees

9. frames + decision tree

10. Implementation of Decision Learning Tree.

11. Info on decision-trees

12. trading accuracy in decision trees

 

 
Powered by phpBB® Forum Software