Skip to content

Issue 9148 - 'pure' is broken - #3626

Merged
WalterBright merged 7 commits into
dlang:masterfrom
9rnsr:fix9148
Nov 13, 2014
Merged

WalterBright merged 7 commits into
dlang:masterfrom
9rnsr:fix9148

Conversation

@9rnsr

@9rnsr 9rnsr commented Jun 6, 2014

Copy link
Copy Markdown
Contributor

https://issues.dlang.org/show_bug.cgi?id=9148

A nested function inside pure function should also be typed as pure, and considered as weak purity function.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why should this pass?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

foo1 is implicitly marked as pure, so accessing global data g will be disallowed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new behaviour introduced by this pull request, right? I guess this makes some sense, but it is a breaking language change. Also, I'd prefer to just have attribute inference for local functions instead because that is more general and wouldn't be a possible cause of annoyance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not new behavior. In 2.065 and git-head, foo1() is not explicitly typed as pure but its purity violation is correctly checked by Expression::checkPurity.

void test9148a() pure
{
    static int g;
    void foo1() { ++g; } // pure function 'foo1' cannot access mutable static data 'g'
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is broken behaviour. I would suggest to indeed stop incorrectly reporting the purity violation, but this can break code unless this is taken care of by e.g. adding attribute inference for local functions. I guess it is ok to merge this as is for now, because it can be fixed later.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@9rnsr: That example does not show broken behaviour. The return type of test() would be int delegate()[]. Then the calls f[0]() and f[1]() in main are impure and the behaviour is not at all surprising. I am just saying that banning ++g categorically is not the right thing to do here. It is perfectly valid for a pure function to compute a result that contains impure delegates. It just may not call those itself. Purity for nested functions should be inferred based on the nested function body and not based on whether the enclosing function is pure. However, I am not opposed to merging this pull request, this restriction can be lifted later. I'll file some issues as soon as this is merged. (Another thing that is still missing is inference of the 'immutable' attribute.) The pull fixes the main concerns of issue 9148 though. Thanks!

@jmdavis: There is no reason to infer purity if the function is not actually pure and this is just going to cause a compile time error.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no reason to infer purity if the function is not actually pure and this is just going to cause a compile time error.

Well, foo1 is within a pure function, so inferring purity makes some sense. What doesn't make sense IMHO is that the outer function be legally pure given that it has a mutable static variable in it. But assume for a moment that foo1 is trying to access a global variable rather than a local static which shouldn't even be legal. If that were the case, then the outer function is properly pure, and it then becomes a question of whether it makes more sense for foo1 to be inferred as pure (resulting in an error if it's not), or if it makes more sense for foo1 to be inferred as impure and then be an error for being inside of a pure function. I'm not sure that it matters much which (though given what's going on with the outer function having a mutable static variable in it that it doesn't use, I suspect that the compiler would unfortunately only complain about an impure foo1 being called rather than it being declared in the first place).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scope of a static variable is completely unimportant. As long as a pure function does not access a mutable static variable, then everything is fine. Also, besides being called, an impure nested function can be passed around as a value. The following code is fine:

int delegate() getCounterIncrementor()pure{
    static int counter = 0;
    return ()=>counter++;
}

getCounterIncrementor does not access any mutable static variables nor does it call any functions that are not pure, hence it can be pure. The following must be (and is already) illegal though:

int foo()pure{
    return getCounterIncrementor()();
}

I.e. there are already enough type checks to make sure that static variables are never accessed within a pure function. Computing using impure functions is not impure as long as those functions are not called. A function that composes two non-pure functions, for example, is still a pure function.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type of test() would be int delegate()[]. Then the calls f0 and f1 in main are impure and the behaviour is not at all surprising.

By returning a tuple instead of an array, you can see the behavior that pure delegate call f[0]() will be violated by the impure f[1]() call.

Ok @tghr, now I'm probably understanding what you saying. With simple case, declaring impure nested function inside pure function would be possible.
But I'm really not sure that is possible with complex cases (and useful or not). So today, I cannot say anything more than that.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand these concerns at all. f[0]() is a weakly pure call. There simply is no possible issue here.

@yebblies

yebblies commented Jun 9, 2014

Copy link
Copy Markdown
Contributor

So should I reopen #2790 ?

@9rnsr

9rnsr commented Jun 9, 2014

Copy link
Copy Markdown
Contributor Author

@yebblies No, by fixing 9148, the error message issue will also be naturally fixed.

I added diagnostic test case for 9620.

@yebblies

yebblies commented Jun 9, 2014

Copy link
Copy Markdown
Contributor

No, by fixing 9148, the error message issue will also be naturally fixed.

Even better!

@9rnsr

9rnsr commented Sep 7, 2014

Copy link
Copy Markdown
Contributor Author

I also fixed a lambda attribute inference case (test9148e() in compilable/testInference.d).
For that, now phobos fix is necessary: dlang/phobos#2493

@9rnsr

9rnsr commented Sep 8, 2014

Copy link
Copy Markdown
Contributor Author

PR is re-enableb by the Phobos tweaking.

@WalterBright
WalterBright merged commit 2774054 into dlang:master Nov 13, 2014
@denis-sh

Copy link
Copy Markdown
Contributor

What happened here? Was it finally accepted or just accidentally merged with #3956?

@denis-sh

Copy link
Copy Markdown
Contributor

@9rnsr, sorry for bothering but could you confirm this is really accepted?

@9rnsr

9rnsr commented Nov 16, 2014

Copy link
Copy Markdown
Contributor Author

I don't know about any discussion and approval over this PR so I had kept a distance from dmd development for a while.

@denis-sh

Copy link
Copy Markdown
Contributor

Thanks.

@WalterBright, could you comment on this pull state please?

@9rnsr
9rnsr deleted the fix9148 branch January 20, 2015 06:53
MartinNowak added a commit that referenced this pull request Aug 30, 2015
[REG2.067/2.068] Issue 14781 & 14962 - fix problematic purity inference introduced in #3626
ibuclaw pushed a commit to ibuclaw/dmd that referenced this pull request Jul 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants