Comment #0 by qs.il.paperinik — 2023-09-18T15:03:23Z
One can explicitly run (“check”) invariants of aggregates using a reference (pointer to struct/union type, object handle of a class) as the argument of an `assert` statement. This is an bad feature: It looks like something that it isn’t, namely (merely) checking if the reference is `null`. In almost all cases one encounters `assert` (reading or writing), it asserts that a boolean condition is true, and a reference is a boolean condition: `if (r)` is equivalent to `if (r !is null)`. While opinions may differ if leaving `!is null` implicit is good or bad style, it certainly is widely known and understood. However, `assert` weirdly special-cases references and using `!is null` is *required* if mere `null` checking is desired.
I suggest a new construct to check invariants: The `invariant` keyword after `assert`, such that it is patently obvious what the intent is and what happens:
```d
Class c = …;
assert(c); // deprecated
assert(c !is null); // Step 1
assert invariant(c); // Step 2
Struct s;
assert(&s); // deprecated
assert invariant(s);
```
For class handles, where the `assert` checking for `null` really means something, the fact that `assert` does two (quite different) things is clearly expressed and (by context) unneeded steps can be left out.
Of course, `assert invariant` can only be used with an aggregate value is passed to it. It differs from `assert` in that structs/union objects are not passed to it by pointer, but “normally”.
Also, it does not perform a `null` check, but requires that the reference is not `null`.
Alternatively, `invariant(s)` can be made a primary expression that executes the invariants and evaluates to `true`; then, uses of `assert` to check invariants can state intent properly:
```d
Class c = …;
assert(c); // deprecated
assert(c && invariant(c)); // okay
assert(c !is null && invariant(c)); // good
Struct s = …;
assert(&s); // deprecated
assert(invariant(s)); // good
```
Comment #1 by robert.schadek — 2024-12-13T19:30:52Z