www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - pure functions

reply Ivy Encarnacion <iencarnacion gmail.com> writes:
Can pure functions throw exceptions on its arguments? Also, how 
can it perform impure operations?
Sep 12 2016
next sibling parent sarn <sarn theartofmachinery.com> writes:
On Tuesday, 13 September 2016 at 03:33:04 UTC, Ivy Encarnacion 
wrote:
 Can pure functions throw exceptions on its arguments?
You can throw exceptions for whatever reasons from a function marked pure: void foo() pure { throw new Exception("nope"); } void main() { foo(); }
 Also, how can it perform impure operations?
Well, the point of pure is to restrict you from doing that. Is there something specific you're trying to do?
Sep 12 2016
prev sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, September 13, 2016 03:33:04 Ivy Encarnacion via Digitalmars-d-
learn wrote:
 Can pure functions throw exceptions on its arguments? Also, how
 can it perform impure operations?
Yes, as long as the exception's constructor is pure, a pure function can throw an exception. However, whether a pure function can do impure operations depends on what you mean by that. A pure function cannot call any function that is not pure (except in debug blocks, which circumvent pure purely for debug purposes and should not be used in normal code). That's part of being pure. But "pure" in the D sense really doesn't have anything to do with functional purity except insofar as it helps enable functional purity, so if when you're talking about a pure function doing an impure operation, you mean doing something that isn't functionally pure, then it can so long as the function's that it's calling are all pure. _All_ that pure means in D is that the function cannot access any mutable, global state or call any functions that aren't pure. At this point, it would be far more accurate for it to be called noglobal than pure, but it's pure because when it was introduced, it was much closer to functionally pure (but far less useful). Originally, pure functions had to have parameters which were immutable or implicitly convertible to immutable so that the function could be functionally pure. That requirement no longer exists, but when a pure function does meet those requirements, there are optimizations that the compiler can do based on functional purity. For instance, a pure function which is functionally pure (i.e. if given the same arguments, it will always result in the same return value) will only be called once with a given set of arguments within an expression even if it's called multiple times. e.g. auto result = pureFunc(a) * pureFunc(a); would result in only one call to pureFunc if pureFunc's parameters are immutable or implicitly convertible to immutable, and the result will be reused. But if the paramaters are not immutable or implicitly convertible to immutable, then it's not functionally pure, and the calls cannot be optimized. Most pure functions can't be optimized like that. On the whole, pure is just a way to guarantee that a function is only using what it's given via its arguments and not doing stuff like saving state in static or global variables. Being able to optimize based on pure when it's actually functionally pure is a just a nice bonus that pops up occasionally. For a more in-depth look at D's purity, you should read http://klickverbot.at/blog/2012/05/purity-in-d/ - Jonathan M Davis
Sep 12 2016
parent reply Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 13 September 2016 at 06:59:10 UTC, Jonathan M Davis 
wrote:
 On Tuesday, September 13, 2016 03:33:04 Ivy Encarnacion via 
 Digitalmars-d- learn wrote:

  A pure function cannot call any function that is not pure [...]
I've read that a lot but it's not true. A pure function can call impure function. The restriction is, that the impure function called within the pure function does not depend or mutate on state existing outside of that function. If the called function changes local variable, it has no bearing on outside the scope. Here a contrived example in C. size_t strlen(const char *str); is pure. If I define it this way for example: size_t my_strlen(const char *str) { char temp[50]; strlcpy(temp, str, sizeof temp); /* strlcpy is not pure as it mutates something outside of its "scope" */ return strlen(str); } That function is pure. There is no visible change outside of it. my_strlen and strlen have exactly the same properties.
Sep 13 2016
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/13/16 4:08 PM, Patrick Schluter wrote:
 On Tuesday, 13 September 2016 at 06:59:10 UTC, Jonathan M Davis wrote:
 On Tuesday, September 13, 2016 03:33:04 Ivy Encarnacion via
 Digitalmars-d- learn wrote:

  A pure function cannot call any function that is not pure [...]
I've read that a lot but it's not true. A pure function can call impure function. The restriction is, that the impure function called within the pure function does not depend or mutate on state existing outside of that function. If the called function changes local variable, it has no bearing on outside the scope.
D defines pure differently. You are allowed to declare a function is pure if it takes (and possibly changes) mutable references. It can be called by pure functions, but will not be optimized in the same way one would expect traditional pure functions to be optimized. We call it "weak-pure". In D, an "impure" function is defined exactly as one that accesses mutable global state. Everything else can be declared pure. The one exception is memory allocation. -Steve
Sep 13 2016
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Tuesday, September 13, 2016 20:08:22 Patrick Schluter via Digitalmars-d-
learn wrote:
 On Tuesday, 13 September 2016 at 06:59:10 UTC, Jonathan M Davis

 wrote:
 On Tuesday, September 13, 2016 03:33:04 Ivy Encarnacion via

 Digitalmars-d- learn wrote:
  A pure function cannot call any function that is not pure [...]
I've read that a lot but it's not true. A pure function can call impure function. The restriction is, that the impure function called within the pure function does not depend or mutate on state existing outside of that function. If the called function changes local variable, it has no bearing on outside the scope. Here a contrived example in C. size_t strlen(const char *str); is pure. If I define it this way for example: size_t my_strlen(const char *str) { char temp[50]; strlcpy(temp, str, sizeof temp); /* strlcpy is not pure as it mutates something outside of its "scope" */ return strlen(str); } That function is pure. There is no visible change outside of it. my_strlen and strlen have exactly the same properties.
That's because you're talking about functional purity and _not_ D's pure. If you want to talk about D's pure, you pretty much need to forget about functional purity. While D's pure allows you to get functional purity, it's actually something different. It would be far more accurate at this point if it were called something like noglobal. Actual, functional purity really only comes into play when a pure function's parameters are immutable or implicitly convertible to immutable, at which point the compiler can guarantee that the same arguments to the function will result in the function returning the same result. Sometimes, pure functions whose parameters are immutable or implicitly convertible to immutable are referred to as strongly pure functions, whereas those whose parameters aren't are called weakly pure. So-called strongly pure functions are what you need if you want to talk about functional purity, whereas so-called weakly pure functions are still pure as far as D is concerned, because they don't violate the functional purity of a strongly pure function if they're called by it. Originally, for a function to be pure in D, it _had_ to have parameters which were immutable or implicitly convertible to immutable, which actually was functionally pure, but it was too restrictive to be useful, so pure was expanded to what it is now, which makes it so that it's not really about functional purity anymore even though it enables functional purity in a way that the compiler can detect it and optimize for it. But when a D programmer talks about a function that's imppure, they're generally not talking about functional purity but about whether it's marked with pure or inferred as pure by the compiler, and per that definition, the code that you have above _is_ pure. In a way, what you're trying to prove about impure in D is both right and wrong, because we're dealing with conflicting definitions of purity here. When discussing pure in D, if you want to talk about whether a function is functionally pure in the sense that one would normally talk about pure functions outside of D, then you need to clearly state that you're talking about functional purity and not about D's pure. When simply saying that something is pure or not, folks here are going to expect you to be talking about D's definition of purity. By the way, the only ways to get around pure are: 1. use debug blocks (where pure is ignored in order to facilite debugging). 2. use an extern(*) other than extern(D) so that the body of the function doesn't have to be marked pure like the prototype does (since other types of linkage don't actually use pure), allowing you to lie to the compiler. 3. use function pointers and cast an impure function pointer to a pure one and thereby lie to the compiler. So, there are a couple of ways to fool the compiler, but there's only one wayt that's sanctioned by it, and it's only intended for debugging purposes. - Jonathan M Davis
Sep 13 2016