Bug 14781 – [REG2.067] impure delegate to pure function context should be able to modify context
Status
RESOLVED
Resolution
FIXED
Severity
regression
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2015-07-07T15:56:00Z
Last change time
2015-09-02T04:10:18Z
Keywords
pull, rejects-valid
Assigned to
nobody
Creator
schveiguy
Comments
Comment #0 by schveiguy — 2015-07-07T15:56:10Z
In a followup to issue 9148, which made this illegal:
int impureFuncCall() { static int g; return g; }
auto foo(out int delegate() pure pureDg) pure {
int x;
auto bar()() {
impureFuncCall();
x = 1; // Error: impure function 'bar' cannot access variable 'x'
// declared in enclosing pure function 'foo'
}
pureDg = &(bar!());
int dg() pure { return x;}
return &dg;
}
This should be allowed. This doesn't violate purity of the returned delegate because the context pointer is mutable -- it's weak pure.
This is similar to how a class can have pure and impure functions both accessing the same data.
Comment #3 by verylonglogin.reg — 2015-07-08T16:54:02Z
(In reply to Steven Schveighoffer from comment #0)
> In a followup to issue 9148, which made this illegal:
>
> int impureFuncCall() { static int g; return g; }
> auto foo(out int delegate() pure pureDg) pure {
> int x;
> auto bar()() {
> impureFuncCall();
> x = 1; // Error: impure function 'bar' cannot access variable
> 'x'
> // declared in enclosing pure function 'foo'
> }
>
> pureDg = &(bar!());
>
> int dg() pure { return x;}
> return &dg;
> }
>
>
> This should be allowed.
> ...
Do you mean this code should compile? If so, either pure function `bar` can call an impure function or impure delegate is implicitly convertible to a pure one.
If you are opening an issue with an enhancement please provide a clear and concise testcase. Thanks.
Comment #4 by schveiguy — 2015-07-08T18:22:05Z
(In reply to Denis Shelomovskij from comment #3)
> Do you mean this code should compile?
Yes.
> If so, either pure function `bar` can
> call an impure function or impure delegate is implicitly convertible to a
> pure one.
No, but I made an error in the example from what I meant.
should be:
auto foo(out int delegate() impureDg) pure {
...
impureDg = &(bar!());
> If you are opening an issue with an enhancement please provide a clear and
> concise testcase. Thanks.
It's hard to make a test case that "should compile" without making an error with no compiler to help you :D
Really, the issue is that bar doesn't compile, not that the impure delegate can't be assigned.
Comment #5 by verylonglogin.reg — 2015-07-08T18:58:55Z
(In reply to Steven Schveighoffer from comment #4)
> (In reply to Denis Shelomovskij from comment #3)
>
> > Do you mean this code should compile?
>
> Yes.
>
> > If so, either pure function `bar` can
> > call an impure function or impure delegate is implicitly convertible to a
> > pure one.
>
> No, but I made an error in the example from what I meant.
>
> should be:
>
> auto foo(out int delegate() impureDg) pure {
>
> ...
>
> impureDg = &(bar!());
>
> > If you are opening an issue with an enhancement please provide a clear and
> > concise testcase. Thanks.
>
> It's hard to make a test case that "should compile" without making an error
> with no compiler to help you :D
>
> Really, the issue is that bar doesn't compile, not that the impure delegate
> can't be assigned.
Then this function isn't strongly pure anymore:
---
T f() pure;
---
if `T` is `int delegate()`.
Is everybody OK with this?
Comment #6 by ag0aep6g — 2015-07-08T19:33:23Z
(In reply to Denis Shelomovskij from comment #5)
> Then this function isn't strongly pure anymore:
> ---
> T f() pure;
> ---
> if `T` is `int delegate()`.
>
> Is everybody OK with this?
I think that's already not strongly pure. `int delegate()` has a mutable indirection in the context pointer. So a function that returns such a delegate can't be strongly pure.
See http://klickverbot.at/blog/2012/05/purity-in-d/#indirections_in_the_return_type
An example with the delegate type:
----
struct S
{
int x = 1;
int method() {return x++;}
}
int delegate() f() pure
{
return &(new S).method;
}
void main()
{
auto dg1 = f();
version(all) auto dg2 = f();
else auto dg2 = dg1; /* This would be equivalent to the above if f were strongly pure. */
import std.stdio;
writeln(dg1()); /* "1" */
writeln(dg1()); /* "2" */
writeln(dg2()); /* "1" or "3", depending on the version above */
}
----
Comment #7 by k.hara.pg — 2015-08-28T03:48:43Z
I change the importance to regression, because the introduced behavior since 2.067 rejects valid code.