September 18, 2023 [Issue 24149] New: Improve invariant checking with assert | ||||
---|---|---|---|---|
| ||||
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@puremagic.com Reporter: qs.il.paperinik@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 ``` -- |
Copyright © 1999-2021 by the D Language Foundation