Fully transitive const is not necessary

Georg Wrede georg at nospam.org
Thu Apr 3 17:28:56 PDT 2008


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.

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.

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

(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/.

If the programmer wants to guarantee that c doesn't change during f's 
invocation, then the invocation of f should be put in a synchronized 
block. This might be the case if c has a complicated state (with several 
fields).

> A function is pure or it isn't, there really isn't any room for 
> "unstable" purity, or the point of purity is lost.
> 
> Look at it another way. You can take the value of the bits pushed on the 
> stack as arguments to a pure function, and compare that with previous 
> bits passed to the same function, and if there's a binary bit match, you 
> can skip calling the function and return a previously cached result.
> 
> If that cannot be done, then the function is NOT pure.

I wonder if that's so simple when we allow non-POD type arguments?

Of course, if you're speaking metaphorically here, then that's another 
thing. But the same literal bit pattern of course could mean the same 
object referred to, only that now it suddenly contains other data.

To further clarify,

If a pure function gets a tree t passed to it, and makes a (potentially 
very complicated and) deep search into it, then the only thing the 
function's pureness guarantees is that if the particular nodes and 
leaves it's looked at stay the same, then it should return the same 
result the next time.

The rest of the tree could undergo severe changes in between, or even 
during an invocation of the pure function, for all it knows. (Of course 
this is academic, but tries to illustrate the issue literally.)

In practice we wouldn't want that, but that's not relevant to the 
Pureness Issue.



More information about the Digitalmars-d mailing list