On Fri, 18 Mar 2011 20:06:16 -0400, Don <nos...@nospam.com> wrote:

Steven Schveighoffer wrote:
On Fri, 18 Mar 2011 14:35:27 -0400, Don <nos...@nospam.com> wrote:

Steven Schveighoffer wrote:
On Fri, 18 Mar 2011 04:34:54 -0400, Don <nos...@nospam.com> wrote:

Steven Schveighoffer Wrote:

As long as the delegate does not access shared/global data, it should be able to be pure. Even delegates which modify TLS data should be able to be pure (weak-pure, but still pure).

TLS variables are global and must not be accessed from any function marked as pure. With regard to purity, there isn't any difference between shared and TLS variables.
 However, it's still not shared.
 This, for example, is a weak pure function:
 void foo(int *n) pure { *n = 5;}
 Because TLS variables are not shared, you should be able to do this:
 int x;
 void bar()
{
  foo(&x);
}

Yes, that compiles fine. But bar() is not pure.

But you are right, there is a huge difference between a local reference to TLS data and directly accessing TLS data -- the latter can be obscured from the compiler, resulting in the compiler thinking the function can be strong pure. So I don't know exactly how to mitigate this, but in my mind, it feels like this should work:
 int foo(bool cond, lazy int n) pure { if(cond) return n; return 0;}
 int x;
 void bar()
{
   foo(x == 4, x = 5);
}
It seems not too different from the above example where you pass the address of x. But obviously the x = 5 delegate cannot be pure (it modifies TLS data). We may have no recourse to get this to work. It may be a lost cause, and you just can't have lazy variables for pure functions.

It's not a lost cause, it's a two-liner!
mtype.c line 5045:

                 if (fparam->storageClass & STClazy)
                 {
- error(0, "cannot have lazy parameters to a pure function");
+                    tf->purity = PUREweak;
+                    break;
                 }

This is a bit conservative: it would be possible to allow lazy parameters to be marked as pure, which would allow them to be strongly pure. But that would probably not be worth the extra complexity.
I'm not sure this works. Aren't you allowed to pass in a delegate to a lazy parameter?

Yes.

 For example:
 shared int x;
 int foo()
{
   return x;
}
 int bar(lazy int n) pure
{
   return n;
}
 void baz()
{
   bar(&foo);
}
 or alternatively:
 void baz()
{
   bar(x);
}

This compiles just fine. (Well, you need to use bar(foo) not bar(&foo)).
But if you try to mark baz() as pure, here's what you get:

test0.d(135): Error: pure function 'baz' cannot call impure function 'foo'

But does this make sense? A pure function (bar) is reading a shared integer via foo, I thought that was a big no-no?

or for the second case:

test0.d(136): Error: pure function 'baz' cannot access mutable static data 'x'

bar is just weakly pure.

But I wasn't saying baz is pure, I was saying bar is pure (probably should be more diverse in the names). But I'm concerned about a pure function being able to indirectly read/write shared data. Does this make sense? I guess a weak-pure function acts like a normal function when called from a normal-function. Is that why it's ok? Will there not be an expectation that a pure function will not read/write shared data that will be broken (i.e. why did the compiler allow this, I thought I was safe from this!)?

So is the rule that if you pass a non-pure delegate into a pure function it's automatically weak-pure? If so, does this not mean we need two versions of pure functions that take delegates, one that takes a pure delegate, and one that takes a non-pure one? Otherwise, how do you know what's strong and what's weak? For example, a weak pure function is strong when called from a strong-pure function, so you could say if the calling function is pure, the call is strong-pure. But wouldn't you need separate generated code for the two cases?

I guess you can see from the number of question marks, I'm not sure about this at all, either way :) If you think it will work, then I trust your judgment.

-Steve

Reply via email to