Re: breaks (was Re: Need to sell Smalltalk)

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: breaks (was Re: Need to sell Smalltalk)

David Simmons
"Steve Wart" <[hidden email]> wrote in message
news:Qe2k6.132886$[hidden email]...

> I hate to wade into this one, but what the hell.
>
> "switch" statements are kind of neat in a way, since they are not really
> semantically the same as a nested collection of boolean tests.
>
> Since this discussion seems to have been about syntax so far, this seems
> worth mentioning.
>
> What is really going on (okay, assuming one knows what the compiler is
> *really* doing), is that a "jump table" is generated.

You should not *assume* that the compiler will or should build a jump table.
In fact, that is just an optimization for the special situation where the
cases are all literal numeric constants (effectively enum values).

In general, a switch is a sequence of nested (arbitrarily complex and
dynamic) if expressions with the additional ability (via break/no-break) to
share/combine condition actions.

======
Switches have distinct value in OO languages like Smalltalk because:

1. They enable control flow decision rules to be succinctly and clearly
co-located for explicit (intention revealing) ease of reference, maintenance
and understanding. Which also reduces method clutter and confusion.

2. They enable efficient and best use flow of control for non-trivial
*value* decisions.

Innapropriate OO language use would be using switch or if control flow
constructs for decisions based on <type> behavior.

Conversely, not using switch or if control flow constructs for decisions
based on values of a given <type> is equally innappropriate (i.e., using
messaging and discrete methods instead of conditional control flow
constructs).

Situations arise where both type and value conditions need to be
intermingled. This is a gray area but it suggests design work is still in
progress.

Use of the following switch-like substitute via OO languages is *poor* use
of OO facilities and is *not* intention revealing:

    selectorIndex := someLikelyComplexExpressionCallChain.
    selector := #(selectorA selectorB ...) at: selectorIndex.
    expr perform: selector

Use of a selector as a state machine a gray area:

    stateActionSelector := nextStateSelector.
    nextStateSelector := self computeNextStateSelector.
    self perform: stateActionSelector.
======

Here are the forms used in SmallScript and QKS Smalltalk
--------------------------------------------------------

    "" SmallScript form
    result := switch(cond) [
        case exprA:
            statements1.
            break.
        case exprB:
            statements2.   "" B will fall through and also do statements3
        case exprC:        "" SmallScript allows case combining
        case exprD:
            statements3.
            break.
        default:
            statements.
            break.
    ].

    "QKS Smalltalk form (which, as you'd expect works in SmallScript)"
    result := (Switch new)
        case: [exprA] do: [
            statements1
        ];
        case: [exprB] do: [
            statements2.
            statements3. "case actions must be duplicated in Smalltalk"
        ];
        case: [exprC] do: [
            statements3  "case actions must be duplicated in Smalltalk"
        ];
        case: [exprD] do: [
            statements3  "case actions must be duplicated in Smalltalk"
        ];
        default: [
            statements
        ];
        on: cond.

The above examples also illustrate that switch expressions can support
combining of cases to share a single sequence of actions.

Also noting that QKS Smalltalk does not require the cases to be declared as
a block [expr], that is optional. The case expressions can be any form of
expression. If they are a block expression, they may optionally take an
argument which is the switch condition.

In both SmallScript and Smalltalk forms the entire switch expression and all
its blocks are inlined.

However, the evaluation rule is that each case is tested via an equality
message. At the first case where the equality message applied to the <case>
and the <cond> returns true, the search for a matching case *stops* and the
the cases statements are executed and returned as the result of the switch
expression.

A hash or direct lookup "table" for cases is a compiler optimization (used
as much as possible in C/C++ compilers) where all the cases are numeric
values, and the switch <cond> type is also a numeric value. Which in C/C++
is all your allowed to use within a switch expression. However, it does not
need to be all your allowed in Smalltalk, etc.

The switch equality messages are:

    "Smalltalk forms"
        #on:                #=
        #equivalentlyOn:    #=~
        #exactlyOn:         #==

    "" SmallScript forms
    switch(cond)            #=
    switch:on(cond)         #=
    switch:equal...(cond)   #=
    switch:equiv...(cond)   #=~
    switch:is(cond)         #==
    switch:ident...(cond)   #==
    switch:exact...(cond)   #==

    "" or any binary message selector (e.g.)
    switch:=(cond)          #=
    switch:=~(cond)         #=~
    switch:==(cond)         #==
    switch:==~(cond)        #==~

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

>
> Wouldn't the equivalent construct in Smalltalk would be a dictionary whose
> values are blocks?
>
> Then you could initialize something like this:
>
> switch := Dictionary new
>     at: #doSomethingCondition put: [ self doSomething ];
>     at: #continueCondition put: [];
>     at: #breakCondition put: [ ^self bailout ];
>     yourself.
>
> then later refer to it like
>
>     conditions do: [ :condition |
>         (switch at: condition ifAbsent: [ self defaultConditionBlock ])
> value ]
>
> So it's not all in one method. I suppose if that were an important
> consideration (hard to picture why), you probably wouldn't be using
> Smalltalk anyhow.
>
> But this does seem more compact and powerful than what you could do with a
C

> "switch" statement.
>
> Steve
>
> "Jeffrey Odell" <[hidden email]> wrote in message
> news:RmRj6.41$[hidden email]...
> >
> > "A SERFer" <[hidden email]> wrote in message
> news:[hidden email]...
> > > Ron Jeffries <[hidden email]> writes:
> > >
> > > >On Fri, 16 Feb 2001 14:30:22 GMT, Chris Lopeman <[hidden email]>
> > > >wrote:
> > > >Well, I guess you don't have an example.
> > > >
> > > >I have found it valuable to use languages as they were intended to be
> > > >used by their designers. It seems to push new ideas into my head. So
I
> > > >don't try to program FORTRAN in C or C in Pascal or Smalltalk. Works
> > > >for me.
> > >
> [ more stuff ]
>
>


Reply | Threaded
Open this post in threaded view
|

Re: breaks (was Re: Need to sell Smalltalk)

Dave Harris-3
[hidden email] (David Simmons) wrote (abridged):
> [Some stuff about Smalltalk in general]

Does this need to be cross-posted to the Dolphin group? I should think
that anyone interested in general Smalltalk issues would read
comp.lang.smalltalk directly. This discussion is now in 4 groups,
which is surely too many.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      [hidden email]      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."


Reply | Threaded
Open this post in threaded view
|

Re: breaks (was Re: Need to sell Smalltalk)

Steve Wart-3
In reply to this post by David Simmons
"David Simmons" <[hidden email]> wrote

> "Steve Wart" <[hidden email]>
> > I hate to wade into this one, but what the hell.
> >
> > "switch" statements are kind of neat in a way, since they are not really
> > semantically the same as a nested collection of boolean tests.
> >
> > Since this discussion seems to have been about syntax so far, this seems
> > worth mentioning.
> >
> > What is really going on (okay, assuming one knows what the compiler is
> > *really* doing), is that a "jump table" is generated.
>
> You should not *assume* that the compiler will or should build a jump
table.
> In fact, that is just an optimization for the special situation where the
> cases are all literal numeric constants (effectively enum values).

sure.

> In general, a switch is a sequence of nested (arbitrarily complex and
> dynamic) if expressions with the additional ability (via break/no-break)
to
> share/combine condition actions.
>
> ======
> Switches have distinct value in OO languages like Smalltalk because:
>
> 1. They enable control flow decision rules to be succinctly and clearly
> co-located for explicit (intention revealing) ease of reference,
maintenance

> and understanding. Which also reduces method clutter and confusion.
>
> 2. They enable efficient and best use flow of control for non-trivial
> *value* decisions.
>
> Innapropriate OO language use would be using switch or if control flow
> constructs for decisions based on <type> behavior.
>
> Conversely, not using switch or if control flow constructs for decisions
> based on values of a given <type> is equally innappropriate (i.e., using
> messaging and discrete methods instead of conditional control flow
> constructs).
>
> Situations arise where both type and value conditions need to be
> intermingled. This is a gray area but it suggests design work is still in
> progress.

I'm not sure I've ever missed using a switch statement in ST, although I
have used 'em in C code, but that was years ago before I understood the
distinction between type and value conditions. Okay, I confess, I still
don't understand the distinction. Maybe an example?

> Use of the following switch-like substitute via OO languages is *poor* use
> of OO facilities and is *not* intention revealing:
>
>     selectorIndex := someLikelyComplexExpressionCallChain.
>     selector := #(selectorA selectorB ...) at: selectorIndex.
>     expr perform: selector
>
> Use of a selector as a state machine a gray area:
>
>     stateActionSelector := nextStateSelector.
>     nextStateSelector := self computeNextStateSelector.
>     self perform: stateActionSelector.

State machines are the only case I've ever really used a switch statement in
C code. The problem with writing state machines this way, is that although
they usually work (there is a simple mapping between a state diagram and the
case statements), my experience has been that you need to completely rewrite
them if your state machine changes, even a little bit. Not to mention that
state transition diagrams do not map nicely into ASCII documentation, and
paper-based diagrams usually vanish a few days after you finish coding up
your parser :(

For a while I thought it would be interesting in Smalltalk to use classes to
represent the states, and then have polymorphic methods which do the state
transitions, but never took it anywhere. I have heard that state-based
network software is brittle; what is it about state machines that make them
a gray area for you?

> ======
>
> Here are the forms used in SmallScript and QKS Smalltalk
> --------------------------------------------------------
>
>     "" SmallScript form
>     result := switch(cond) [
>         case exprA:
>             statements1.
>             break.
>         case exprB:
>             statements2.   "" B will fall through and also do statements3
>         case exprC:        "" SmallScript allows case combining
>         case exprD:
>             statements3.
>             break.
>         default:
>             statements.
>             break.
>     ].
>
>     "QKS Smalltalk form (which, as you'd expect works in SmallScript)"
>     result := (Switch new)
>         case: [exprA] do: [
>             statements1
>         ];
>         case: [exprB] do: [
>             statements2.
>             statements3. "case actions must be duplicated in Smalltalk"
>         ];
>         case: [exprC] do: [
>             statements3  "case actions must be duplicated in Smalltalk"
>         ];
>         case: [exprD] do: [
>             statements3  "case actions must be duplicated in Smalltalk"
>         ];
>         default: [
>             statements
>         ];
>         on: cond.
>
> The above examples also illustrate that switch expressions can support
> combining of cases to share a single sequence of actions.
>
[ some implementation notes omitted ]

I'm still not convinced this type of statment is really necessary in
Smalltalk. I think judicious use of polymorphism is easier to
maintain/extend than a case construct. No reason not to add it if you need
it, but I don't think there is a strong enough case to add anything to the
compiler.

As I indicated, you can emulate a jump table with a dictionary, which you
correctly point out is not necessarily how a "real" switch statement would
be compiled, it's still more efficient than cascading messages (although if
the number of cascaded tests becomes an issue, there are probably bigger
problems to deal with).

Cheers,
Steve


Reply | Threaded
Open this post in threaded view
|

Re: breaks (was Re: Need to sell Smalltalk)

David Simmons
"Steve Wart" <[hidden email]> wrote in message
news:aAmk6.140233$[hidden email]...
>
> "David Simmons" <[hidden email]> wrote
> > "Steve Wart" <[hidden email]>
> > > I hate to wade into this one, but what the hell.
> > >
> > > "switch" statements are kind of neat in a way, since they are not
really
> > > semantically the same as a nested collection of boolean tests.
> > >
> > > Since this discussion seems to have been about syntax so far, this
seems
> > > worth mentioning.
> > >
> > > What is really going on (okay, assuming one knows what the compiler is
> > > *really* doing), is that a "jump table" is generated.
> >
> > You should not *assume* that the compiler will or should build a jump
> table.
> > In fact, that is just an optimization for the special situation where
the

> > cases are all literal numeric constants (effectively enum values).
>
> sure.
>
> > In general, a switch is a sequence of nested (arbitrarily complex and
> > dynamic) if expressions with the additional ability (via break/no-break)
> to
> > share/combine condition actions.
> >
> > ======
> > Switches have distinct value in OO languages like Smalltalk because:
> >
> > 1. They enable control flow decision rules to be succinctly and clearly
> > co-located for explicit (intention revealing) ease of reference,
> maintenance
> > and understanding. Which also reduces method clutter and confusion.
> >
> > 2. They enable efficient and best use flow of control for non-trivial
> > *value* decisions.
> >
> > Innapropriate OO language use would be using switch or if control flow
> > constructs for decisions based on <type> behavior.
> >
> > Conversely, not using switch or if control flow constructs for decisions
> > based on values of a given <type> is equally innappropriate (i.e., using
> > messaging and discrete methods instead of conditional control flow
> > constructs).
> >
> > Situations arise where both type and value conditions need to be
> > intermingled. This is a gray area but it suggests design work is still
in
> > progress.
>
> I'm not sure I've ever missed using a switch statement in ST, although I
> have used 'em in C code, but that was years ago before I understood the
> distinction between type and value conditions. Okay, I confess, I still
> don't understand the distinction. Maybe an example?

A simple but general case is that of numbers.

Values like:

    -1, 58, 98784374, 12

Are all instances of the same type: <SmallInteger>

The same kind of simple but general case can frequently be seen for classes
such as <String> and <Symbol>. Obviously you don't want to write methods on
those classes or helper classes just to deal with specific values.

By logical extension, you don't want to write methods or helper class
methods to break out each of the decisions with regard to specific
(instances) values of user defined (classes) types.

>
> > Use of the following switch-like substitute via OO languages is *poor*
use

> > of OO facilities and is *not* intention revealing:
> >
> >     selectorIndex := someLikelyComplexExpressionCallChain.
> >     selector := #(selectorA selectorB ...) at: selectorIndex.
> >     expr perform: selector
> >
> > Use of a selector as a state machine a gray area:
> >
> >     stateActionSelector := nextStateSelector.
> >     nextStateSelector := self computeNextStateSelector.
> >     self perform: stateActionSelector.
>
> State machines are the only case I've ever really used a switch statement
in
> C code. The problem with writing state machines this way, is that although
> they usually work (there is a simple mapping between a state diagram and
the
> case statements), my experience has been that you need to completely
rewrite
> them if your state machine changes, even a little bit. Not to mention that
> state transition diagrams do not map nicely into ASCII documentation, and
> paper-based diagrams usually vanish a few days after you finish coding up
> your parser :(
>
> For a while I thought it would be interesting in Smalltalk to use classes
to
> represent the states, and then have polymorphic methods which do the state
> transitions, but never took it anywhere. I have heard that state-based
> network software is brittle; what is it about state machines that make
them
> a gray area for you?

I think you misunderstood my "gray area" comment. I was not making any
comment on "state machines". I was commenting on the "use of selectors with
#perform:" as a mechanism for implementing state machines.

In my opinion Smalltalk is an excellent language for building state
machines.

I've built uncountable state machines over the years in many different
languages. They have their place and in that place they are not brittle --
quite the opposite. A brittle state machine is just a state machine whose
design was not well planned or was just poor. The "brittle" factor may also
come in where "performance" overrides design -- but that is a whole other
topic.

A state machine, by definition, is something where every state and
transition is known and therefore it should be impossible to have unknown
states or transition situations. That means that state machines are easier
than many other problem types for both understanding and developing good
designs which should make it easier to avoid brittle design issues.

If you introduce new states or transitions, that is a different state
machine. The idea that adding new states or transitions requires
regenerating the state machine, or if hand built, updating the state
decision code, does not make state machines inherently brittle.

By analogy, that would be like saying that using OO is brittle because when
your design changes you may need to refactor your classes and methods and
that can be hard without good tools and can lead to fragile designs?

>
> > ======
> >
> > Here are the forms used in SmallScript and QKS Smalltalk
> > --------------------------------------------------------
> >
> >     "" SmallScript form
> >     result := switch(cond) [
> >         case exprA:
> >             statements1.
> >             break.
> >         case exprB:
> >             statements2.   "" B will fall through and also do
statements3

> >         case exprC:        "" SmallScript allows case combining
> >         case exprD:
> >             statements3.
> >             break.
> >         default:
> >             statements.
> >             break.
> >     ].
> >
> >     "QKS Smalltalk form (which, as you'd expect works in SmallScript)"
> >     result := (Switch new)
> >         case: [exprA] do: [
> >             statements1
> >         ];
> >         case: [exprB] do: [
> >             statements2.
> >             statements3. "case actions must be duplicated in Smalltalk"
> >         ];
> >         case: [exprC] do: [
> >             statements3  "case actions must be duplicated in Smalltalk"
> >         ];
> >         case: [exprD] do: [
> >             statements3  "case actions must be duplicated in Smalltalk"
> >         ];
> >         default: [
> >             statements
> >         ];
> >         on: cond.
> >
> > The above examples also illustrate that switch expressions can support
> > combining of cases to share a single sequence of actions.
> >
> [ some implementation notes omitted ]
>
> I'm still not convinced this type of statment is really necessary in
> Smalltalk. I think judicious use of polymorphism is easier to
> maintain/extend than a case construct. No reason not to add it if you need
> it, but I don't think there is a strong enough case to add anything to the
> compiler.

Hmm. "Polymorphism" is about types and their behavior, not about creating
individual behaviors for discrete values of a type. If one finds oneself
trying to do that, then I suggest that there is some confused understanding
of types, polymorphism, and OO in general.

Where polymorphism would be appropriate to your ultimate problem but you
just have a set of values for a given type, like integers, you may need to
define classes to represent the different values so they can have individual
behavior.

I.e. You need to map a set of values (think of it as data not objects) of a
given type into objects (instances of different types of objects). This is a
fairly common situation where switch statements and lookup tables are both
appropriate solutions.

One of the criteria affecting the choice of which one to use is whether or
not the mapping can be reduced to a simple key<->value relationship, or
whether it has more complex dependencies and relational combinatorics.

However, the idea that polymorphism should be used to manage decisions about
values of a given type is just innapropriate.  If you have a set of numbers
or a set of strings that you need to map to some decision set, writing a lot
methods for each of the value test cases is just obfuscating the intent and
muddling the design (it is also very inefficient).

Just like one can twist functional and procedural language constructs to
avoid cases where OO functionality would serve best, one can try to twist OO
to avoid functional and procedural control flow capabilities -- that doesn't
mean (just because one is using OO) that it is a best practice solution.

>
> As I indicated, you can emulate a jump table with a dictionary, which you
> correctly point out is not necessarily how a "real" switch statement would
> be compiled, it's still more efficient than cascading messages (although
if
> the number of cascaded tests becomes an issue, there are probably bigger
> problems to deal with).

I don't understand the "cascaded" messages comment -- if the compiler
optimizes the code then the actual declaration form is irrelevant with
regard to efficiency.

Therefore other criteria apply to the choice of cascading. Such as, that it
is just more natural for Smalltalk style than ultra long message names as
others have suggested. And, the cascade form supports design of clean and
simple <Switch> class built with a handful of methods which enable support
for all the switch semantics in portable (non-optimized/slow) Smalltalk
code.

Both the switch forms I cited in my original post are fully implemented and
optimized in the SmallScript language and QKS Smalltalk language
implementations I designed and built (we've had switches in our Smalltalk
for nearly 10 years).

For certain classes of problems, their use makes it easier to understand a
decision matrix (flow of control). Optimization by the compiler results in
performance that is significantly faster than trying to contort Smalltalk OO
facilities innapropriately.

----
Our compilers have always optimized our code and I have always designed both
our object model and instruction sets for optimization.

When I first came to Smalltalk many years ago, and even up until about five
years ago, most of the Smalltalk compilers were surprisingly poor at
generating code.

It was surprising how even simple things like peephole optimization and
constant folding were not done. (let alone important things like block and
context management optimizations). I don't know where they stand now, but
from discussion I've had with other implementors I believe they have
improved quite a bit.


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

>
> Cheers,
> Steve


Reply | Threaded
Open this post in threaded view
|

Re: breaks (was Re: Need to sell Smalltalk)

Steve Wart-3
"David Simmons" <[hidden email]>
> "Steve Wart" <[hidden email]> wrote
> >
[ snip ]

> > I'm not sure I've ever missed using a switch statement in ST, although I
> > have used 'em in C code, but that was years ago before I understood the
> > distinction between type and value conditions. Okay, I confess, I still
> > don't understand the distinction. Maybe an example?
>
> A simple but general case is that of numbers.
>
> Values like:
>
>     -1, 58, 98784374, 12
>
> Are all instances of the same type: <SmallInteger>
>
> The same kind of simple but general case can frequently be seen for
classes
> such as <String> and <Symbol>. Obviously you don't want to write methods
on
> those classes or helper classes just to deal with specific values.
>
> By logical extension, you don't want to write methods or helper class
> methods to break out each of the decisions with regard to specific
> (instances) values of user defined (classes) types.

So when you talk about distinguishing between values and types, does it
refer only to these "basic" classes or does this argument extend to other
classes as well? I think I understand your argument for avoiding
polymorphism for specific instances as a general principle.

I've seen a lot of code that looks something like

(aCompany label = 'XYZ Customer')
    ifTrue: [ aCompany doSomething ].

I consider this poor practice, but programmers (especially beginning
programmers) often find it difficult to deal with special cases. I suppose
you could subclass roles of an object and use double-dispatching and
polymorphism to avoid these situations, but there is a risk of introducing
multiple points of failure which can be hard to track down (again,
especially for beginning programmers).

One alternative would be to have multiple variants of a method signature on
a given class.

e.g.
    Number>>#add: <anInteger>
    Number>>#add: <aFloat>
    Number>>#add: <aPoint>

And double-dispatching becomes unnecessary.

It might be simple to extend this (although perhaps terribly wrong) to allow
forms like:

    MyStateMachine>>#input: 3
    MyStateMachine>>#input: -12322
    MyStateMachine>>#input: #endToken
    MyStateMachine>>#input: <anEndOfStreamSignal>

Then the compiler can bury the logic (even generate a jump table if
appropriate), but the programmer is dealing only with one case in each
variant of the method.

> > For a while I thought it would be interesting in Smalltalk to use
classes to
> > represent the states, and then have polymorphic methods which do the
state
> > transitions, but never took it anywhere. I have heard that state-based
> > network software is brittle; what is it about state machines that make
them
> > a gray area for you?
>
> I think you misunderstood my "gray area" comment. I was not making any
> comment on "state machines". I was commenting on the "use of selectors
with
> #perform:" as a mechanism for implementing state machines.
>
> In my opinion Smalltalk is an excellent language for building state
> machines.
>
> I've built uncountable state machines over the years in many different
> languages. They have their place and in that place they are not brittle --
> quite the opposite. A brittle state machine is just a state machine whose
> design was not well planned or was just poor. The "brittle" factor may
also
> come in where "performance" overrides design -- but that is a whole other
> topic.

I guess different application domains impose different design patterns. I
wonder if there is a state-machine design pattern that could provide a nice
high-level abstraction for dealing with a large number of cases where the
"switch" statement seems to be required?

> A state machine, by definition, is something where every state and
> transition is known and therefore it should be impossible to have unknown
> states or transition situations. That means that state machines are easier
> than many other problem types for both understanding and developing good
> designs which should make it easier to avoid brittle design issues.
>
> If you introduce new states or transitions, that is a different state
> machine. The idea that adding new states or transitions requires
> regenerating the state machine, or if hand built, updating the state
> decision code, does not make state machines inherently brittle.
>
> By analogy, that would be like saying that using OO is brittle because
when
> your design changes you may need to refactor your classes and methods and
> that can be hard without good tools and can lead to fragile designs?

Well, state machines are not encapsulated. By definition the state is of the
entire machine, so changing one part of it can affect the whole thing. OO is
a bit different in theory, if only because it provides better support for
hiding the brittle stuff. OTOH, if all my behavior is in one method, then OO
doesn't buy much.

> > [ some implementation notes omitted ]
> >
> > I'm still not convinced this type of statment is really necessary in
> > Smalltalk. I think judicious use of polymorphism is easier to
> > maintain/extend than a case construct. No reason not to add it if you
need
> > it, but I don't think there is a strong enough case to add anything to
the
> > compiler.
>
> Hmm. "Polymorphism" is about types and their behavior, not about creating
> individual behaviors for discrete values of a type. If one finds oneself
> trying to do that, then I suggest that there is some confused
understanding
> of types, polymorphism, and OO in general.
>
[ more about polymorphism and values ]

This makes sense. My concerns are mostly that I find the "switch" statement
inelegant and subject to abuse. It may be that it is useful for certain
types of applications (e.g. tokenizers), but languages with an equivalent
statement were around before the first Smalltalk environments were built. If
it is so useful (especially for parsers and compilers), why was it omitted
from the language in the first place?

My feeling is that rather before lifting a construct that exists with
various degrees of sophistication in a number of other languages that we
should understand what it means in an OO context. If you're the one writing
the compiler, and you already have this understanding, then you really are
the only one you have to answer to.

For me, it's a curiosity. I use the tools I'm given and try to impose my own
sense of aestetics (which is always changing).

[ notes on optimization omitted ]

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

Steve