Fully transitive const is not necessary

Steven Schveighoffer schveiguy at yahoo.com
Sat Apr 5 06:03:14 PDT 2008


"Georg Wrede" wrote
> Steven Schveighoffer wrote:
>> "Georg Wrede" wrote
>>>Walter Bright wrote:
>>>>Bill Baxter wrote:
>>>>
>>>>>So does that mean
>>>>>
>>>>>  pure int f(const Class c)
>>>>>  { ...
>>>>>  }
>>>>>
>>>>>will *not* be allowed?  Because some part of c *could* change, even if 
>>>>>it's not f() doing the changing.  I.e. another thread could be changing 
>>>>>c concurrently.
>>>>
>>>>Right. That declaration of f is erroneous.
>>>
>>>I'd disagree.
>>>
>>>Whether a function is pure or not, has nothing to do with whether c could 
>>>change or not.
>>
>> The question is, should pure functions be protected from other threads 
>> changing c?   I think Walter wants this to be true, and for that, c must 
>> be invariant.  I think Walter is trying to promote a different definition 
>> for pure than what you are thinking of.
>
> Hmm. (There ought to be a law against stealing other people's words!!! And 
> jail time for changing them subtly and inconspicuously!)
>
> Hundreds of (otherwise unnecessary) posts even in this NG are written 
> every month, just because two people argue on something, that in the end 
> turns out to be just them having different notions of what a word means. 
> And reading those posts wastes everyones time!

Sorry.  Usually, to convince "the world" of an opinion, you must argue 
continuously with the single doubter.  Otherwise, it looks like you give in 
:)

> And, in that case, it would have been prudent to clarify this as a comment 
> to "What is pure and what is not". Not only for my sake, but for all the 
> readers who've seen this post stay undisputed or uncommented.

I still don't know the answer to this, as I've never used 'pure' and I'm 
pretty sure Walter intends to use pure in a different way than it has been 
used before :)

>>>Take, for example sin(x). We all know that it's pure, period. Now, 
>>>whether x changes between two consecutive invocations or not, is 
>>>irrelevant. Of course you get a different result. And you should.
>>
>> sin(x) is a completely different animal, because x is not a reference 
>> type, it is pushed on the stack, and the pure function has the only 
>> reference to it.  Nothing can change x while sin is running.
>
> So you mean that Walter's pure implies that the argument has to be 
> Petrified? (Dammit, I don't even dare to use the normal words for stuff 
> anymore, so I make my own words! Petrified here simply means "we know it 
> won't change". Vague, I know.)

Only for reference types.  For value types (such as structs without 
pointers/references and basic types like int), they are copied on the stack 
every time they are passed to a function, and so they are guaranteed to be 
unique.  That is why sin(x) doesn't need 'Petrified' data, because a 
guaranteed unique copy of x (presumably a double?) is made.

>
> Does it also mean that the pure function itself causes this Petrified 
> thing, or is it the programmer's responsibility to Petrify the object 
> before passing it?

I would guess that the caller has to ensure this for reference/pointer 
types, otherwise, the compiler can't tell whether the data pointed to is not 
going to change during the function with a different thread.  BTW, the 
keyword that means 'Petrified' is invariant.

>
>>>But pure, IMHO, means (1) the function is guaranteed to give the same 
>>>result every time /if/ the input is the same (like sin(x) does), (2) it 
>>>does not change anything at all anywhere, it's only way of affecting life 
>>>is by its return value, (3) it doesn't access info from non-constants 
>>>anywhere.
>>>
>>>Now, to the issue between
>>>
>>>    (1)pure int f(const Class c)
>>>    (2)pure int f(Class c)
>>>
>>>I'd say that, since a Pure function promises not to change /anything/ 
>>>(other than its return value, of course) anywhere, this means a pure 
>>>function /simply has to implicitly treat its arguments as unchangeable/!
>>>
>>>Therefore, depending on what A/W want, either:
>>>
>>> - a pure function has to have const decorated parameters only (1)
>>> - and (2) would be a syntax error
>>>
>>>or
>>>
>>> - a pure function's parameters are implicitly const, and (1) is then a 
>>> syntax error
>>
>> If the arguments must be invariant, then they cannot be implicitly cast. 
>> I understand what you are saying, but I think A/W want something 
>> different.
>
> Arrgh. You lost me here. (I'm getting paranoid: did you write this because 
> it says "implicitly const" above? What if it had been just "petrified", as 
> in "somehow just known not to change while the pure function is running"?)

I'm saying, if Walter and Andrei define pure functions as ONLY taking 
invariant data, then 2 must be the syntax error.  In fact, to get technical, 
1 is a syntax error also, it should be:

pure int f(invariant Class c);

as const does not guarantee that c will not change, it just guarantees that 
f will not change c.  const in D means 'constant through this view'

Of course, I could also be wrong, and they do not intend to implement pure 
functions as requiring invariant reference parameters.  In that case, I've 
totally misunderstood the whole point of having pure functions, and I'd 
hazard to guess it negates the reason for having invariant in the first 
place :)

>>>(Not making the latter a syntax error isn't technically impossible, but 
>>>for those learning the language and the casual readers of ex. magazine 
>>>articles, this would wreak havoc with their understanding D.)
>>>
>>>*Back to concurrency*, if someone changes c in mid-run, then it's the 
>>>programmer's fault. It's his headache. The function f only guarantees not 
>>>to change c /by itself/.
>>
>> I think this is what A/W want to prevent.  Otherwise, all this touting 
>> about pure functions being the way to multiprogram in D is not completely 
>> true, you still have to deal with multithreadded issues.
>
> Heh, I always thought everybody already knew and agreed on that.
>
> Running pure (as in "my" definition ;-( ) functions on atomic data would 
> be nice and fast. No concurrency issues, IMHO.
>
> But obviously, with any reference type one has to have some kind of 
> mechanism that guarantees atomicity of access.

No need to guarantee atomicity for data that will not change.  That is why I 
think invariant reference parameters are necessary.

>
>> Walter has said before he wants multithreaded programming to "just work" 
>> without having to do any locking, just like FP languages have.
>
> That'd be excellent. Problem is, then the data would have to be Petrified 
> all the FP time.

Not only all FP time, but all time.  If you are executing a pure function in 
one thread and a non-pure function in another thread, and both have 
references to the same data, this won't work without synchronization issues 
if the non-pure function has a writable reference, but the FP function has a 
'Petrified' reference.

Sorry to be so confusing.  It's really tough to explain things that I'm not 
totally sure of, but I have no choice, as Walter is never specific about 
what the rules will be :)  We have to imply them from his statements of how 
pure functions will work.

-Steve 





More information about the Digitalmars-d mailing list