Subject: Nested WHERE statements

From: Guy Steele <[email-masked]>
Date: Tue, 15 Sep 92 16:21:07 EDT

At this juncture, now that we have discussed FORALL statements
and their nesting, I would like to re-raise an issue that appeared
in the "big yellow book" distributed in January but has disappeared
since then.  It might be appropriate to discuss this in October.

(g) Nested WHERE statements.

Here is the text of a proposal once sent to X3J3:

| Briefly put, the less WHERE is like IF, the more difficult it is to
| translate existing serial codes into array notation.  Such codes tend to
| have the general structure of one or more DO loops iterating over array
| indices and surrounding a body of code to be applied to array elements.
| Conversion to array notation frequently involves simply deleting the DO
| loops and changing array element references to array sections or whole
| array references.  If the loop body contains logical IF statements, these
| are easily converted to WHERE statements.  The same is true for translating
| IF-THEN constructs to WHERE constructs, except in two cases.  If the IF
| constructs are nested (or contain IF statements), or if ELSE IF is used,
| then conversion suddenly becomes disproportionately complex, requiring the
| user to create temporary variables or duplicate mask expressions and to use
| explicit .AND. operators to simulate the effects of nesting.
| 
| Users also find it confusing that ELSEWHERE is syntactically and
| semantically analogous to ELSE rather than to ELSE IF.
| 
| [We] ... propose that the syntax of WHERE constructs be extended and
| changed to have the form
| 
| 	where-construct       is  where-construct-stmt
| 				    [ where-body-construct ]...
| 				  [ elsewhere-stmt
| 				    [ where-body-construct ]... ]...
| 				  [ where-else-stmt
| 				    [ where-body-construct ]... ]
| 				  end-where-stmt
| 
| 	where-construct-stmt  is  WHERE ( mask-expr )
| 
| 	elsewhere-stmt        is  ELSE WHERE ( mask-expr )
| 
| 	where-else-stmt       is  ELSE
| 
| 	end-where-stmt        is  END WHERE
| 
| 	mask-expr             is  logical-expr
| 
| 	where-body-construct  is  assignment-stmt
| 			      or  where-stmt
| 			      or  where-construct
| 	
| Constraint: In each assignment-stmt, the mask-expr and the variable
| 	being defined must be arrays of the same shape.  If a
| 	where-construct contains a where-stmt, an elsewhere-stmt,
| 	or another where-construct, then the two mask-expr's must
| 	be arrays of the same shape.
| 
| The meaning of such statements may be understood by rewrite rules.  First
| one may eliminate all occurrences of ELSE WHERE:
| 
| 	WHERE (m1)				WHERE (m1)
| 	  xxx					  xxx
| 	ELSE WHERE (m2)		becomes		ELSE
| 	  yyy					  WHERE (m2)
| 	END WHERE				    yyy
| 						  END WHERE
| 						END WHERE
| 
| where xxx and yyy represent any sequences of statements, so long as the
| original WHERE, ELSE WHERE, and END WHERE match, and the ELSE WHERE is the
| first ELSE WHERE of the construct (that is, yyy may include additional ELSE
| WHERE or ELSE statements of the construct).  Next one eliminates ELSE:
| 
| 	WHERE (m)				temp = m
| 	  xxx					WHERE (temp)
| 	ELSE			becomes		  xxx
| 	  yyy					END WHERE
| 	END WHERE				WHERE (.NOT. temp)
| 						  yyy
| 						END WHERE
| 
| Finally one eliminates nested WHERE constructs:
| 
| 	WHERE (m1)				temp = m1
| 	  xxx					WHERE (temp)
| 	  WHERE (m2)				  xxx
| 	    yyy			becomes		END WHERE
| 	  END WHERE				WHERE (temp .AND. (m2))
| 	  zzz					  yyy
| 	END WHERE				END WHERE
| 						WHERE (temp)
| 						  zzz
| 						END WHERE
| 
| and similarly for nested WHERE statements.
| 
| The effects of these rules will surely be a familiar or obvious possibility
| to all the members of the committee; I enumerate them explicitly here only
| so that there can be no doubt as to the meaning I intend to support.
| 
| Such rewriting rules are simple for a compiler to apply, or the code may
| easily be compiled even more directly.  But such transformations are
| tedious for our users to make by hand and result in code that is
| unnecessarily clumsy and difficult to maintain.
| 
| One might propose to make WHERE and IF even more similar by making two
| other changes.  First, require the noise word THERE to appear in a WHERE
| and ELSE WHERE statement after the parenthesized mask-expr, in exactly the
| same way that the noise word THEN must appear in IF and ELSE IF statements.
| (Read aloud, the results might sound a trifle old-fashioned--"Where knights
| dare not go, there be dragons!"--but technically would be as grammatically
| correct English as the results of reading an IF construct aloud.)  Second,
| allow a WHERE construct to be named, and allow the name to appear in ELSE
| WHERE, ELSE, and END WHERE statements.  I do not feel very strongly one way
| or the other about these no doubt obvious points, but offer them for your
| consideration lest the possibilities be overlooked.

[End of proposal as sent to X3J3.]

Now, for compatibility with Fortran 90, HPF should continue to
use ELSEWHERE instead of ELSE, but this causes no ambiguity:

      WHERE(...)
	...
      ELSE WHERE(...)
	...
      ELSEWHERE
	...
      END WHERE

is perfectly unambiguous, even when blanks are not significant.
Since X3J3 declined to adopt the keyword THERE, it should not be
used in HPF either (alas).

[End of excerpt from yellow book.]

I can't resist noting that the analogy to the IF statement
would be complete if there were also a single-statement form
of WHERE, as in

		WHERE (B .NE. 0.0)  A = A/B

And one could allow the noise-word THERE to be used optionally,
to complete the symmetry...

--Guy

---

From: Guy Steele <[email-masked]>
Date: Tue, 15 Sep 92 16:27:09 EDT

From: Guy Steele <[email-masked]>
   Date: Tue, 15 Sep 92 16:21:07 EDT

   ...

Forgive me; I don't know where my mind was.  Fortran 90
*of course* already has a single-statement form of WHERE.
D-uh.

I'm off to get another cup of coffee ...

--Guy