Against enforce()
Steven Schveighoffer
schveiguy at yahoo.com
Mon Mar 21 05:54:49 PDT 2011
On Fri, 18 Mar 2011 20:06:16 -0400, Don <nospam at nospam.com> wrote:
> Steven Schveighoffer wrote:
>> On Fri, 18 Mar 2011 14:35:27 -0400, Don <nospam at nospam.com> wrote:
>>
>>> Steven Schveighoffer wrote:
>>>> On Fri, 18 Mar 2011 04:34:54 -0400, Don <nospam at 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
More information about the Digitalmars-d
mailing list