Bug 19065 – Struct invariant violated in @safe with T.init

Status
NEW
Severity
enhancement
Priority
P4
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-07-06T08:25:36Z
Last change time
2024-12-13T18:59:31Z
Keywords
safe
Assigned to
No Owner
Creator
FeepingCreature
Moved to GitHub: dmd#19455 →

Comments

Comment #0 by default_357-line — 2018-07-06T08:25:36Z
Consider this code: struct S { @disable this(); bool b = false; this(int) { b = true; } invariant { assert(b == true); } @safe ~this() { } } @safe void main() { S s = S.init; } I believe the appropriate response to this is that invariant checking must be disabled on struct destructors. Struct destructors are supposed to be able to handle T.init anyways; otherwise the behavior of moveEmplace is nonsensical. This problem is, as far as I can tell, completely solved by requiring structs to be either invariant-valid or T.init at destructor call.
Comment #1 by bugzilla — 2018-07-08T02:36:08Z
I think this change defeats the purpose of having an invariant. T.init is supposed to be a valid object, and so should pass the invariant. It's not a bug, it's the way the language is designed to work. To make this modification to the semantics, a fairly compelling use case will be required.
Comment #2 by default_357-line — 2018-07-08T03:01:43Z
T.init having to be a valid object makes structs unusable for value types that contain objects by reference that must not be null, or arrays that must not be empty. At my workplace, this scenario turns up a *lot* when trying to use structs to contain domain data.
Comment #3 by default_357-line — 2018-07-08T03:16:37Z
That said, the only case "invariant on destruction" even comes up, is when changing values via public fields and using the destructor as a kind of "last-ditch invariant check", which imo is largely useless because one by definition you haven't called domain methods on it anyway, and two - if T.init is supposed to be valid, you have to recheck all references for null in the destructor *anyways*, since you can't have the checks in the invariant. The only thing that having to have T.null be a valid object buys you is making it impossible to use invariant for null checks. As far as I can see, the userland code ends up strictly, necessarily more awkward by that rule.
Comment #4 by ali.akhtarzada — 2018-07-12T22:30:55Z
(In reply to Walter Bright from comment #1) > I think this change defeats the purpose of having an invariant. T.init is > supposed to be a valid object, and so should pass the invariant. > > It's not a bug, it's the way the language is designed to work. > > To make this modification to the semantics, a fairly compelling use case > will be required. Does this mean the compile time constructed value of T must be a valid runtime constructed value of T to be able to use invariants?
Comment #5 by default_357-line — 2018-07-23T08:45:36Z
Yep.
Comment #6 by robert.schadek — 2024-12-13T18:59:31Z
THIS ISSUE HAS BEEN MOVED TO GITHUB https://github.com/dlang/dmd/issues/19455 DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB