Bug 4974 – Cannot have pure constructor due to impure invariant
Status
RESOLVED
Resolution
FIXED
Severity
normal
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
Other
OS
Linux
Creation time
2010-10-02T02:49:00Z
Last change time
2011-07-10T00:31:56Z
Assigned to
nobody
Creator
issues.dlang
Comments
Comment #0 by issues.dlang — 2010-10-02T02:49:43Z
This code
struct S
{
this(int x) pure
{
this.x = x;
}
invariant()
{
assert(x >= 0);
}
int x;
}
void main()
{
}
results in this compilation error
Error: pure function 'this' cannot call impure function '__invariant'
d.d(8): Error: function d.S.__invariant () is not callable using argument types ()
Error: pure function 'this' cannot call impure function '__invariant'
Maybe this will be fixed by the changes that Don has suggested, I don't know. But with dmd 2.049, it is, as far as I can tell, impossible to have a pure constructor and an invariant - and the lack of a pure constructor really limits how much you can make pure. There doesn't appear to be a way to make invariant pure either.
So, I see three possible solutions
1. Make it possible to mark invariants as pure.
2. Consider invariant pure as long as it doesn't access mutable globals.
3. Have invariant act like it's pure but don't care whether it really is or (probably better) output a warning if it isn't.
The one I'd like best would be #3 on the theory that it would allow you to use writeln() and have a pure invariant. The invariant would be compiled out in release builds, so it wouldn't affect release code anyway. And if it means that writeln() doesn't print as often due to a pure function call being optimized out, then tough luck. It would just be temporary debugging code anyway. And since there's a halfway decent chance that pure function calls don't get cached in debug builds anyway, then you really wouldn't lose anything.
Now, assuming that #3 isn't acceptable, #2 would likely be the best, since it wouldn't require changing the grammar to somehow mark an invariant as pure, but any of the three would be better than the current situation.
Comment #1 by bearophile_hugs — 2010-10-02T04:29:22Z
See also bug 3856
Comment #2 by clugdbug — 2010-11-08T19:14:18Z
In DMD2.050, 'pure invariant()' compiles, which was your solution 1. Not sure if that's enough to mark the bug as fixed.
Comment #3 by issues.dlang — 2010-11-08T22:36:47Z
Well, marking an invariant as pure does seem to actually make it pure which is a definite improvement, though honestly, I rather like the idea of the compiler acting like all invariants are pure so that you can have pure functions and still be able to use stuff like writeln() in your invariant when debugging. As it is, marking an invariant as pure does seem to make it possible to have pure functions, but it eliminates your ability to print debug statements in invariants.
Comment #4 by bearophile_hugs — 2010-11-09T04:13:41Z
(In reply to comment #3)
> I rather like the idea of the compiler
> acting like all invariants are pure so that you can have pure functions and
> still be able to use stuff like writeln() in your invariant when debugging. As
> it is, marking an invariant as pure does seem to make it possible to have pure
> functions, but it eliminates your ability to print debug statements in
> invariants.
A possible solution using the idea in bug 5125 (syntax is temporary):
pure nothrow bool isDebug() {
debug return true;
return false;
}
@optional_tag(ifDebug(), pure) invariant() { ...
Comment #5 by clugdbug — 2010-11-09T04:33:50Z
(In reply to comment #3)
> As
> it is, marking an invariant as pure does seem to make it possible to have pure
> functions, but it eliminates your ability to print debug statements in
> invariants.
I don't think that problem is unique to invariants. It's the same issue as logging in pure functions, and in CTFE functions.
You should be able to do printf-style debugging in ANY pure function.
Comment #6 by bearophile_hugs — 2010-11-09T04:40:16Z
(In reply to comment #5)
> You should be able to do printf-style debugging in ANY pure function.
Do you mean something like this?
pure void foo() {
debug { printf("foo"); }
}
And even giving the compiler an explicit debug{} tag that is tricky. In general writing is a side effect. So if your programs output is the text it produces, its output may change according to how much the compiler optimizes away pure function calls.
Comment #7 by bearophile_hugs — 2010-11-09T04:45:54Z
(In reply to comment #5)
> You should be able to do printf-style debugging in ANY pure function.
Another simple solution is to add a special pure printf version, that's just a pure alias of printf:
pure void foo() {
pureprintf("foo");
}
pureprintf() is not meant for normal output, but just for debugging and the like. And the person that uses pureprintf() has to remember that it's not deterministic, its output may appear or not appear.
Comment #8 by yebblies — 2011-07-10T00:31:56Z
Now that we have printing from pure functions inside debug conditions, I think this is all solved.