Comment #0 by matti.niemenmaa+dbugzilla — 2006-11-15T07:34:26Z
This code should fail regardless of whether the constructor is commented out or not:
class Foo {
// this() {}
invariant {
assert (false);
}
}
void main() {
Foo foo = new Foo();
}
Yet, it only does if the constructor is explicitly specified. The invariant is not called from the automatically inserted constructor, even though there's no reason why it shouldn't be.
Comment #1 by smjg — 2009-01-10T11:30:46Z
*** Bug 2184 has been marked as a duplicate of this bug. ***
Comment #2 by bearophile_hugs — 2010-06-17T13:08:26Z
*** Issue 4331 has been marked as a duplicate of this issue. ***
Comment #3 by andrei — 2010-11-26T11:39:12Z
The example needs parens:
class Foo {
// this() {}
invariant {
assert (false);
}
}
void main() {
Foo foo = new Foo();
}
Comment #4 by andrei — 2010-11-26T11:39:39Z
Forgot to add the actual parens :o).
class Foo {
// this() {}
invariant() {
assert (false);
}
}
void main() {
Foo foo = new Foo();
}
Comment #5 by yebblies — 2011-06-17T07:53:50Z
What should happen in these cases?
class A
{
shared invariant {}
}
class A
{
immutable invariant {}
}
Comment #6 by k.hara.pg — 2011-06-20T05:45:02Z
Autogenerated destructor has same problem:
----
import core.stdc.stdio : printf;
class Foo {
invariant() {
printf("Foo.invariant\n");
}
}
void main() {
Foo foo = new Foo();
printf("lifetime of foo\n");
delete foo;
}
----
Should print:
----
Foo.invariant
lifetime of foo
Foo.invariant
----
But current output is:
----
lifetime of foo
----
Comment #7 by yebblies — 2012-01-21T17:21:31Z
*** Issue 7334 has been marked as a duplicate of this issue. ***
Comment #8 by verylonglogin.reg — 2012-10-30T06:05:58Z
Structs have the same problem:
---
import std.stdio;
struct S
{
invariant() { writeln("invariant"); } // never called
// ~this() { writeln("~this"); } // uncomment to call invariant
}
void main()
{
auto s = S();
}
---
Comment #9 by clugdbug — 2012-11-15T00:20:52Z
*** Issue 9019 has been marked as a duplicate of this issue. ***
Comment #10 by bearophile_hugs — 2013-02-06T03:19:45Z
See also Issue 9454
Comment #11 by bugzilla — 2014-11-11T21:11:29Z
I agree that the invariant should run on non-empty struct literals and on destruction.
I'm skeptical, however, of the value of running it on default construction, as those values will always be the .init ones.
Rainer raised an important question for running invariant before class destruction. Because GC finalization order is undetermined an invariant that would check whether some classes's field points to a valid instance could fail because the pointed-to class could already have been finalized.
http://forum.dlang.org/post/[email protected]
Comment #15 by smjg — 2014-11-22T02:02:01Z
(In reply to Walter Bright from comment #11)
> I'm skeptical, however, of the value of running it on default construction,
> as those values will always be the .init ones.
Maybe have a rule that, if the -unittest option is set, autogenerate a unittest to call the invariant on the .init.
Comment #16 by andrei — 2015-01-14T23:43:37Z
I stated this elsewhere, just making sure I don't forget: probably we don't want to invoke invariants during the GC cycle.
Comment #17 by code — 2015-01-15T10:18:44Z
(In reply to Andrei Alexandrescu from comment #16)
> I stated this elsewhere, just making sure I don't forget: probably we don't
> want to invoke invariants during the GC cycle.
Walter has a different opinion on this, I don't follow his argument though.
http://forum.dlang.org/post/[email protected]
Currently it can't be done, because the calls to the invariant are embedded into the generated destructor function.
Also the invariant is called twice, before and after running the destructor. The latter forces one to perform additional cleanup, e.g. setting pointers to null.
Comment #18 by andrei — 2015-01-15T16:03:23Z
(In reply to Martin Nowak from comment #17)
> (In reply to Andrei Alexandrescu from comment #16)
> > I stated this elsewhere, just making sure I don't forget: probably we don't
> > want to invoke invariants during the GC cycle.
>
> Walter has a different opinion on this, I don't follow his argument though.
> http://forum.dlang.org/post/[email protected]
>
> Currently it can't be done, because the calls to the invariant are embedded
> into the generated destructor function.
Well a simple invariant would be:
assert(this.parent.child is this);
which would be placed in some child node, or could be moved in parent like this:
assert(this.child.parent is this);
The invariant involves two objects no matter where you put it.
> Also the invariant is called twice, before and after running the destructor.
> The latter forces one to perform additional cleanup, e.g. setting pointers
> to null.
That's definitely a problem. Invariants are not supposed to hold after destruction.
@RazvanN7 created dlang/dmd pull request #10022 "Fix Issue 519 - Invariant not called from autogenerated class/struct constructor/destructor" fixing this issue:
- Fix Issue 519 - Invariant not called from autogenerated class/struct constructor/destructor
https://github.com/dlang/dmd/pull/10022
Comment #21 by qs.il.paperinik — 2023-01-13T16:38:49Z
Maybe this can be done via a caller-side lowering:
The expression `T(args...)` would become
```d
{
auto result = T(args...);
assert(() @trusted { return &result; }());
return result;
}()
```
The @trusted block is to be able to take the address without dip1000.
Comment #22 by robert.schadek — 2024-12-13T17:47:47Z