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.
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.
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.
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.
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?
- An endless loop occurs.
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.