[Issue 24149] New: Improve invariant checking with assert
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Mon Sep 18 15:03:23 UTC 2023
https://issues.dlang.org/show_bug.cgi?id=24149
Issue ID: 24149
Summary: Improve invariant checking with assert
Product: D
Version: D2
Hardware: All
OS: All
Status: NEW
Severity: enhancement
Priority: P1
Component: dmd
Assignee: nobody at puremagic.com
Reporter: qs.il.paperinik at gmail.com
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
```
--
More information about the Digitalmars-d-bugs
mailing list