Van Snyder wrote:
> Werner Schulz wrote:
> > (o) Extension of CASE:
<snip>
> > CASE( r1<=A<r2, r3<A<=r4, r5,r6,r7 ) ! r stands for range
> > ...
> > CASE( r2<=A<r3, r8,r9 )
> > ...
> > CASE DEFAULT
> > END SELECT
> > where A can be integer or real or character(ASCII).
<snip>
> Roger Glover wrote:
> ! As currently defined, each "case-value-range," such as "r1<=A<r2" or
> ! "r9" must be composed of initialization expressions. And the "A" in
> ! this example is allowed to be any scalar expression. Thus, I think
> ! this proposed syntax could lead to some real parsing and human-
> ! readability nightmares. For exmple, does the "A" in the range have
> ! to be the same as the "A" in the "SELECT CASE" expression?
>
> In 97-114, I proposed SELECT CASE (<expr>) ... CASE (r1 <= * < r2) ...
> where * is a place-holder that refers to the value of <expr>.
Much better! I could possibly be convinced to support this syntax,
but the previous syntax would be disasterous.
> ! In my opinion, the real beauty of the SELECT CASE construct is
> ! that, it is possible for the compiler to set up a hash table
> ! that would reduce the speed of search execution down to the time
> ! required to do an array lookup. This is a so-called O(0) ("order
> ! zero") search.
>
> ! REAL values are much harder to handle in this sort of mechanism.
>
> There have been at least four objections to REAL ranges for CASE
> constructs, of which the above is just one.
>
> Semantically, CASE is no different from IF.
If you believe this, you have not thought out the implications
completely [1]. Even if we were to allow REAL case expressions,
SELECT CASE would still express a limited subset of the semantics
of a block IF.
> The existence of an
> efficient implementation for an important subset of the usages of a
> construct should not be used as an argument against the utility of the
> other usages -- it looks more like an excuse than a reason.
Actually, it is a "motivation." That is, it is a goal or purpose
useful to keep in mind while working with or thinking about the
construct.
> The compiler can, when appropriate, do what Glover suggests. Indexing
> (aka computed GOTO) isn't efficient when the range of integers is large
> compared to the number of them, and doesn't work at all for character
> type when LEN is large.
Unless there is a "second-order hashing" that encodes the cases,
instead of just a simple hash table. Second-order hashing can
still become untenable, but only in much larger and much more
complex cases than all but a tiny fraction of programmers will ever
encounter. It can also add overhead, but not as much as repeated
long jumps on systems with low memory bandwidth.
> Would you expect / hope for use of indexing if you wrote:
> SELECT CASE(J) ; CASE(1) ; ... ; CASE(1000000) ; ... END CASE
> if there were no other cases? Wouldn't hashing be too much clanking
> machinery? I would expect and hope for an IF-tree under-the-covers.
I suppose it would depend on what was inside the "..."s and how
much memory bandwidth is available for instructions. On a Cray
vector machine with one simple assignment under each case, there is
no doubt you are right; in most codes jump times are a non-issue.
On a PC or RISC system with long cache lines and with heaps of code
under either of the "..."s, I would hope for partial second-order
hashing at least [2].
> If REAL ranges of CASE were allowed, there would be nothing to prevent
> the compiler to do what Glover likes (when it's appropriate).
Well then, why not drop some of the other artificial limitations
that separate SELECT CASE semantics from block IF semantics? Why
not allow COMPLEX case expressions? Derived type case expressions?
Array-valued case expressions? Pointer-valued case expressions?
Why not let the "case values" be any expression, and not just an
initialization expression (as it is now)? Why not allow "case
ranges" to overlap? Why not allow multiple comma-separated lists
of case expressions with corresponding multiple comma-separated
lists of case selectors on each CASE statement?
Where does it end?
> One recently raised objection is that a program might have different
> meaning on different platforms, or might compile on some, but not on
> others, because different precisions and rounding methods might cause
> REAL ranges to have different boundaries, or to overlap. This is _no_
> different from the situation with IF, except that with IF you don't get
> any help from the compiler in the case when ranges overlap.
The "no overlap" rule is also an artificial restriction of SELECT
CASE relative to block IF. The difference appears to be that you
have a use for the "no overlap" restriction, but you do not have a
use for the "discrete types only" restriction.
The problem with REALs in your scenario is that "range overlap"
detectable at compile time could be different than "range overlap"
detectable at runtime! Any rule to the contrary would implicitly
prohibit (or at least grossly complicate) cross-platform compiling.
This reasoning is a straight-forward corollary to the reasoning for
the restriction against floating point operations in initialization
expressions.
> If the
> compilers work correctly, one should be able to prevent overlap and
> non-portable behavior by writing
> CASE (A <= * < B) ; ... ; CASE (B <= * < C) ; ...
> or CASE (A <= * <= B) ; ... ; CASE (B+NEAREST(B,1.0) <= * <= C); ...
^^^^^^^^^^^^^^^^
In the first place, in think you mean simply "NEAREST(B,1.0)".
In the second place, this would require the standard to accept a
case value that is not an initialization expression (it contains a
REAL-valued intrinsic); where does it end?
In the third place, there are many other ways "range overlap"
might happen. For example:
CASE ( 3.14159265358979 ); ...
CASE ( 3.14159265358980 ); ...
The compiling environment might see these as the same REAL value
when the runtime environment would not have, or vice versa.
> (I prefer the first), except in the case when the ranges degenerate to
> emptyness (and then the compiler should produce a message).
>
> (This is, by the way, related to the reason to prohibit REAL loop
> inductors: the number of "trips" might vary from platform to platform.)
As is the argument *against* allowing REAL-valued case expressions.
> Other objections are described in paper 97-114. So far, I consider all
> objections to allowing REAL range for CASE to be "excuses," not
> "reasons."
By this reasoning, any argument in favor of any other restricted
syntax that results in SELECT CASE having less functionality than
that of a block IF is also an "excuse."
-------- Cray Research --------- Roger Glover
-- A Silicon Graphics Company -- http://home.cray.com/~glover
[1] Even if we allow REALs and even if I assume you meant simple
chains of IF-ELSEIF-...-ELSE-ENDIF, how does one express the
following as a SELECT CASE?:
IF( firstVar < secondVar ) THEN
...
ELSE IF( abs( thirdVar - fourthVar ) > tolerance() ) THEN
...
ELSE IF( any( firstArray >= secondArray ) ) THEN
...
ELSE
...
END IF
In the spirit of the exercise, I would ask that you not use any
variables or procedures not defined in Fortran or used in the
example. For example, one could define four hash values based on
the four logic choices and have the SELECT CASE choose among them,
but that would be cheating.
[2] Something like this pseudo-assembly-code would be nice:
hashArray(2) = [ addr_4, addr_5 ]
!!! actually registers if register file can be indexed
value = 2 !!! actually a register
JUMP ON( J==1 ) TO addr_3 !!! J actually a register by now
JUMP ON( J==1000000 ) TO addr_1
JUMP TO addr_2
addr_1: value = 1
addr_2: JUMP TO hashArray(value) !!! the only expensive jump
addr_3: ... !!! First Case ("value" is irrelevant)
...
addr_4: ... !!! Second Case ("value" is 1)
...
addr_5: ... !!! End of Construct ("value" is 2)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|