Thread overview
[Issue 9300] Syntax for loop invariants
Dec 17, 2022
Iain Buclaw
Jul 23, 2024
Bolpat
Jul 23, 2024
Bolpat
December 17, 2022
https://issues.dlang.org/show_bug.cgi?id=9300

Iain Buclaw <ibuclaw@gdcproject.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Priority|P2                          |P4

--
July 23, 2024
https://issues.dlang.org/show_bug.cgi?id=9300

Bolpat <qs.il.paperinik@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |qs.il.paperinik@gmail.com

--- Comment #4 from Bolpat <qs.il.paperinik@gmail.com> ---
(In reply to Don from comment #1)
> Compared to an assert, plus a comment, what do they add?

A loop invariant must be true entering the loop and exiting the loop, including the case when the loop runs zero times.

In 2024, the ideal syntax is an invariant block, syntactically identical to
`invariant` blocks in aggregates, but actually more similar to function
contracts:
```d
while (cond)
invariant(inv)
{
    ...
}
```
Which could lower to:
```d
assert(inv);
while (cond)
{
    scope(success) assert(inv);
    ...
}
```

The advantage is alleviating a DRY violation plus documenting intent. Also, getting it right isn’t trivial, actually. It took me a while to realize `scope(success)` would be needed and just putting it at the end of the loop simply isn’t enough.

The lowering above assumes that the condition doesn’t have side-effects. For a
`for` loop, it’s not entirely clear when exactly the invariant would be
checked. Before or after the init? If before, nothing of the init part could be
used as part of the invariant, which makes little sense. If after, expressing
it boils down to:
```d
for (Init; Cond; Inc)
invariant (Inv)
Body;
// lowers to:
for ({ Init; assert(Inv); } Cond; Inc)
{
    scope(success) assert(Inv);
    Body;
}
```

For completeness:
```d
do invariant (Inv) Body; while (Cond);
// lowers to:
assert(Inv);
do { scope(success) assert(Inv); Body; } while (Cond);
```
and
```d
foreach (Var; Agg) invariant (Inv) Body;
// lowers to
assert(Inv);
foreach (Var; Agg) { scope(success) assert(Inv); Body; }
```

--
July 23, 2024
https://issues.dlang.org/show_bug.cgi?id=9300

--- Comment #5 from Bolpat <qs.il.paperinik@gmail.com> ---
It’s not entirely clear if an invariant should be checked if the loop is entered or left via `goto`. My sense is entering should not check the invariant, but exiting, I truly don’t know. `scope(success)` would check it.

--
December 13
https://issues.dlang.org/show_bug.cgi?id=9300

--- Comment #6 from dlangBugzillaToGithub <robert.schadek@posteo.de> ---
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/18512

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB

--