A Case Against the UNTIL Statement would have been accurate, but I could not pass on using a famous phrasal template.
Conditional Iteration with UNTIL
An ABAP language element implements a concept needed to solve a problem in the developer mind. After a learning period, the developer will absorb the pattern and intuitively, effortlessly express a solution in term of the ABAP statement. The statement becomes part of the formal language used to describe a solution that other developers can read and understand.
The
VALUE #( FOR .. THEN ..UNTIL ) expression works well in most cases, it is intuitively understood as a LOOP statement where you can control the index so it has the potential to be widely used.
But I have found one case where this model is broken. So when
FOR UNTIL becomes pervasive in code, it will be used without discrimination and there will be cases where the intuition will be wrong, so it it can be
Considered Harmful.
Challenge
Evaluate the following pseudo code. What do you expect for N = 0 ?
DATA(iota) = VALUE table_of_integer( FOR idx = 0 UNTIL idx = N ( idx ) ).
- For N = 5, we create the table iota = #( ( 0 ) ( 1 ) ( 2 ) ( 3 ) ( 4 ) ).
- For N = 2, we create the table iota = #( ( 0 ) ( 1 ) ).
- For N = 1, we create the table iota = #( ( 0 ) ).
Scroll down for the solution.
The
UNTIL behavior is documented:
- If the iteration variable var has a numeric data type, or the variable is of type d or t, THEN expr is optional. If THEN expr is not specified explicitly, THEN var + 1 is added implicitly or the value of the iteration variable is increased by 1 for every iteration.
- If the termination condition is specified after UNTIL, the logical expression log_exp is evaluated after every iteration step. If the result of the logical expression is true, the iteration is ended. At least one iteration step is executed.
|
So in
FOR .. UNTIL loops,
at least one iteration step is executed. In the example above, if
N = 0 or
-1, -2 actually for any value less than the start value, our test for equality yields an endless loop because the iteration is always executed at least once.
Problem
Note this does not happen with a
FOR .. WHILE expression
- If the termination condition is specified after WHILE, the logical expression log_exp is evaluated after every iteration step. If the result of the logical expression is false, the iteration is ended. If the result of the logical expression is false even before the first iteration step, no iteration steps are executed.
This does not happen with
LOOP AT itab [FROM idx1] [TO idx2]
- If the value of idx2 is less than the value of idx1, no processing takes place.
I currently consider this deviation in the
UNTIL Conditional Iteration a breach of contract. Just like in the case of
SELECT FOR ALL ENTRIES with a empty internal table, the mental model is broken.
Summary
ABAP has been successful at eliminating off by 1 errors in loops with the pervasive LOOP statement.
FOR .. THEN ... UNTIL expressions give us the power to control the loop index. But by enforcing
at least one iteration they break the mental model and yield endless loops.
Although the behavior is documented, I currently consider this a bug. There are more expressive way to specify an endless loop.
- Can you think of a use case for this behavior?
- Can anybody please create an extended syntax check rule for this special case?
Challenge Solution
The issue was observed on the SAP Cloud Platform, ABAP environment. After a trivial refactoring, the unit tests would abort with a runtime problem.
Working with unit tests saved me, again.