www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - confused about pure functions

reply "markusle" <markus.lists gmail.com> writes:
Using dmd 2.058 I can compile the following

pure bool has_path(string paths[], string needle) {

    paths[0] = "bad";

    ... do something else ...

    return false;
}

and change the passed in array "paths". Isn't this a violation of
has_path's pure contract? Shouldn't all pure function parameters
be passed as "in" to avoid side effects. Sorry if I missed
something obvious.
Mar 17 2012
next sibling parent "Adam D. Ruppe" <destructionator gmail.com> writes:
In D, pure means it doesn't have any side effects outside
its parameter list.

It can change what you pass in, but nothing else.


Pass it all in, const, or best of all, immutable params
and it can't change anything - that's the pure you're
probably thinking of.



The reason it lets you change the arguments is so you
can use more functions as pure. Consider that you can
have mutable local variables in a pure function - a
local variable doesn't change the outside world, so
it never breaks the contract.

You might want to use a helper function on your local
variables.


Editing a local variable is allowed, so calling a function
that edits a local variable should be allowed too. As far
as the outside world can tell, this is exactly the same thing.

pure void increment(ref int a) { a++; }
int myInt = 0;
increment(myInt); // is logically the same as myInt++;
// we'd allow myInt++;, so we should allow increment(myInt) too.



But, under the strictest definition of pure, that increment
function wouldn't be allowed. Pure functions can only call
other pure functions.


That's why D pure is a little looser: this /should/ be
allowed. Thus, it can be marked as pure.


Does this break the big contract? No, because editing the
params is a purely local modification - the outside world
doesn't need to care how you build your own local variables.


When combined with transitive immutable, you can create
nice pockets of purity while retaining flexibility in
how you implement the function itself. Only what you
pass and get from it is important.
Mar 17 2012
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 3/17/12 12:02 PM, markusle wrote:
 Using dmd 2.058 I can compile the following

 pure bool has_path(string paths[], string needle) {

 paths[0] = "bad";

 ... do something else ...

 return false;
 }

 and change the passed in array "paths". Isn't this a violation of
 has_path's pure contract? Shouldn't all pure function parameters
 be passed as "in" to avoid side effects. Sorry if I missed
 something obvious.

D's working definition of a pure function is "effect only depends on parameters". Mutating parameters does fit the definition. This is less tight than other languages' definition, but we believe it's a sweet spot between reaping the modularity benefits of purity, and benefiting of the advantages of mutation. Also, not all is lost. If you want to disallow parameter mutation, add "in" to them. That way, you only need to see the function's signature to draw a variety of interesting facts about it. Andrei
Mar 17 2012
prev sibling parent "markusle" <markus.lists gmail.com> writes:
On Saturday, 17 March 2012 at 17:59:12 UTC, Andrei Alexandrescu 
wrote:
 On 3/17/12 12:02 PM, markusle wrote:
 Using dmd 2.058 I can compile the following

 pure bool has_path(string paths[], string needle) {

 paths[0] = "bad";

 ... do something else ...

 return false;
 }

 and change the passed in array "paths". Isn't this a violation 
 of
 has_path's pure contract? Shouldn't all pure function 
 parameters
 be passed as "in" to avoid side effects. Sorry if I missed
 something obvious.

D's working definition of a pure function is "effect only depends on parameters". Mutating parameters does fit the definition. This is less tight than other languages' definition, but we believe it's a sweet spot between reaping the modularity benefits of purity, and benefiting of the advantages of mutation. Also, not all is lost. If you want to disallow parameter mutation, add "in" to them. That way, you only need to see the function's signature to draw a variety of interesting facts about it. Andrei

Thanks a lot for yours and Adam's detailed explanation. This makes much more sense now.
Mar 17 2012