Against enforce()

Don nospam at nospam.com
Fri Mar 18 17:06:16 PDT 2011


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'

or for the second case:

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

bar is just weakly pure.

> The no-shared-data rule prevents you from passing in a shared int 
> reference to a pure function, but how do you stop a delegate from 
> accessing shared data?

Delegates are either marked as pure, or not. In the case above, foo() is 
not pure.



More information about the Digitalmars-d mailing list