Pure functions in D

Steven Schveighoffer schveiguy at yahoo.com
Wed Sep 24 05:34:29 PDT 2008


"Bruno Medeiros" wrote
> Steven Schveighoffer wrote:
>> "Bruno Medeiros" wrote
>>> Steven Schveighoffer wrote:
>>>> Another possibility is that pure functions that accept mutable 
>>>> parameters can only be called from other pure functions, therefore you 
>>>> are guaranteed that the data is not being used in any other thread.
>>>>
>>> I'm almost certain this is the intended behavior, with the addition that 
>>> you can also call that same pure function from an unpure one, only then, 
>>> the compiler will treat the function as being unpure. This is the gist 
>>> of the "partially pure"/"contextually pure" idea: a function is 
>>> considered pure or not dependent on the immutability of the arguments 
>>> with which it's called. This consideration "happens" on every call. 
>>> Since the optimizations to pure functions are made on the call, and not 
>>> on the body of the function, this is perfectly ok.
>>> I don't see any other behavior that isn't either broken, or more limited 
>>> in functionality.
>>
>> One of the benefits that Walter and Andrei's original purity plan 
>> provided was that you could always assume that pure functions did not 
>> have to worry about threading issues.  I think allowing a pure function 
>> that takes mutable arguments to be callable from an unpure function 
>> removes that benefit.  I hope this isn't the case.
>>
>> Of course, if shared/unshared is implemented, and pure functions are only 
>> allowed to be passed 'unshared' mutable data, then the benefit is still 
>> on.
>>
>> I'm just unclear on what Walter is planning.  I admit I didn't read the 
>> whole article, I just saw that quote and thought 'hm... that looks 
>> wrong'.
>>
>>> Also note that in the case where the given (contextually) pure "foo" 
>>> function is called from a pure function, the fact that foo is called 
>>> from a pure function only guarantees that the arguments are not changed 
>>> by anyone else when foo executes, but foo must still be treated as 
>>> unpure. Example:
>>>
>>> pure void foo(int* iptr) {
>>>   (*iptr)++; // side effect
>>> }
>>>
>>>
>>> pure int func() {
>>>   int a = 1;
>>>   foo(&a); // side-effect, cannot optimize this call
>>>   foo(&a); // side-effect, cannot optimize this call
>>>   return a;
>>> }
>>> // Yet func is allways pure.
>>
>> I agree with you, partially pure functions can be called from pure 
>> functions with limited optimization.  But if you allow foo to be called 
>> from an unpure function you could have this problem:
>>
>> int func2()
>> {
>>     static int a = 1;
>>     foo(&a);
>> }
>>
>> Now, if 2 threads are calling func2, you have race conditions and 
>> threading issues in foo, which seems to be a major concern that W/A were 
>> trying to address.  And I hope they do address it, it was the one huge 
>> benefit I saw from pure functions.
>>
>> -Steve
>
> Yes, you can have race and threading issues in foo with that call. But 
> what is the alternative? In the first pure system (in andrei's 
> presentation) that call would not be allowed. So what you would do? You'd 
> have to write another function just like foo (the same code), but that is 
> not marked pure, and use that. But you'd still have the same 
> synchronization problems.
> If you don't want to have those issues, write a foo function that takes 
> invariant parameters.
> The partially pure functions (functions with mutable parameters), which 
> basically have localized side-effects and are deterministic when called 
> from "really-pure" functions, are not there to provide the full effects of 
> really-pure functions. They are just a convenience for the writing the 
> really-pure functions.
>
> (Also, I'd reckon most static/global functions will be partially pure.)

It creates a definitive line which can be used to determine whether or not I 
need to worry about threading.  Having the compiler enforce this I see as a 
huge benefit.  I was hoping to keep that line.

If the compiler enforces that the parameters to foo must be local, either by 
implementing the shared/unshared paradigm or only allowing calling from 
other pure functions, then the line still exists.

It appears that that is the case, as evidenced from other posts.

-Steve 





More information about the Digitalmars-d mailing list