www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Will compiler-enforced pure be too strict?

reply "Craig Black" <craigblack2 cox.net> writes:
Don Clugston wrote:
A function which accesses a global is inherently impure. But,
a function which takes a non-invariant argument, can in theory safely be 
called
from inside a pure function, provided any non-invariant arguments are local
variables, or invariant.

eg.

class C
{
   int numcalls;
   this() { numcalls=0; }
   void foo() { ++numcalls; } // Not pure - but no global side effects.
}

pure int bar(int x)
{
     C c = new C;
     for (int i=0; i<x; ++i) c.foo();
     return c.numcalls;
}

Is bar() pure or not?

Incidentally this type of code currently works in CTFE.

The answer is yes bar is pure even though foo is not, because c is a local variable, so it's non-static fields won't be accessed by other threads. Unless I misunderstand, the rule is that a non-static class/struct variable that is local to a pure function can call a member function if that member function does not access global state. My question is, will the compiler be smart enough to know that bar is pure, even though foo is not? Maybe we need some other keyword to denote that a function does not access any global/static variables. Something like this: localstate void foo() { ++numcalls; } Or perhaps the compiler would be smart enough to know this without the keyword? -Craig
Apr 03 2008
parent reply Don Clugston <dac nospam.com.au> writes:
Craig Black wrote:
 Don Clugston wrote:
 A function which accesses a global is inherently impure. But,
 a function which takes a non-invariant argument, can in theory safely 
 be called
 from inside a pure function, provided any non-invariant arguments are 
 local
 variables, or invariant.

 eg.

 class C
 {
   int numcalls;
   this() { numcalls=0; }
   void foo() { ++numcalls; } // Not pure - but no global side effects.
 }

 pure int bar(int x)
 {
     C c = new C;
     for (int i=0; i<x; ++i) c.foo();
     return c.numcalls;
 }

 Is bar() pure or not?

 Incidentally this type of code currently works in CTFE.

The answer is yes bar is pure even though foo is not, because c is a local variable, so it's non-static fields won't be accessed by other threads. Unless I misunderstand, the rule is that a non-static class/struct variable that is local to a pure function can call a member function if that member function does not access global state. My question is, will the compiler be smart enough to know that bar is pure, even though foo is not? Maybe we need some other keyword to denote that a function does not access any global/static variables. Something like this: localstate void foo() { ++numcalls; } Or perhaps the compiler would be smart enough to know this without the keyword?

I don't see how the compiler could do it, without access to the source code. Also, if the compiler is doing this automatically, then if you add a static variable inside foo(), you are changing the API of the function, and bar() . Even though bar() as written is pure, it can't safely use foo(), since foo() makes no guarantees that it won't become impure some day. I can see a few options -- * very strict pure, bar() above cannot be pure. * some way of signifying (new keyword?) that an arbitrary function has no global state. * allow something like 'pure class'/'pure struct' for a class or struct which is safe to use in circumstances like the above -- a class which contains contains no statics, and which has no functions which access local variables. * allow non-const member functions to be pure, even if they modify 'this'. Probably we'll initally get the first one, but hopefully we'll get something like one of the other options eventually, otherwise pure functions will be very limited.
Apr 04 2008
parent "Craig Black" <craigblack2 cox.net> writes:
"Don Clugston" <dac nospam.com.au> wrote in message 
news:ft4lof$2e9v$1 digitalmars.com...
 Craig Black wrote:
 Don Clugston wrote:
 A function which accesses a global is inherently impure. But,
 a function which takes a non-invariant argument, can in theory safely be 
 called
 from inside a pure function, provided any non-invariant arguments are 
 local
 variables, or invariant.

 eg.

 class C
 {
   int numcalls;
   this() { numcalls=0; }
   void foo() { ++numcalls; } // Not pure - but no global side effects.
 }

 pure int bar(int x)
 {
     C c = new C;
     for (int i=0; i<x; ++i) c.foo();
     return c.numcalls;
 }

 Is bar() pure or not?

 Incidentally this type of code currently works in CTFE.

The answer is yes bar is pure even though foo is not, because c is a local variable, so it's non-static fields won't be accessed by other threads. Unless I misunderstand, the rule is that a non-static class/struct variable that is local to a pure function can call a member function if that member function does not access global state. My question is, will the compiler be smart enough to know that bar is pure, even though foo is not? Maybe we need some other keyword to denote that a function does not access any global/static variables. Something like this: localstate void foo() { ++numcalls; } Or perhaps the compiler would be smart enough to know this without the keyword?

I don't see how the compiler could do it, without access to the source code. Also, if the compiler is doing this automatically, then if you add a static variable inside foo(), you are changing the API of the function, and bar() . Even though bar() as written is pure, it can't safely use foo(), since foo() makes no guarantees that it won't become impure some day. I can see a few options -- * very strict pure, bar() above cannot be pure. * some way of signifying (new keyword?) that an arbitrary function has no global state. * allow something like 'pure class'/'pure struct' for a class or struct which is safe to use in circumstances like the above -- a class which contains contains no statics, and which has no functions which access local variables. * allow non-const member functions to be pure, even if they modify 'this'. Probably we'll initally get the first one, but hopefully we'll get something like one of the other options eventually, otherwise pure functions will be very limited.

I like the second option the best. Maybe "local" keyword? Sorry to change the subject, but even if we do get this, pure is not "The Solution" to concurrency. One thing that is a little disappointing about pure is that it really doesn't help me with my concurrency issues. I need to parallelize a time stamped ordered event queue, and I don't see how pure will help me. I need something more advanced: speculation heuristics about global state. That is, a particular event can execute in parallel (out of order) if certain global state variables don't change. There's a lot to this and like I said, pure doesn't help. Features that would help me with concurrency are (1) static and non-static thread local storage, and (2) a way to prevent a function from accessing global variables (local keyword perhaps). 2 would not be useful for my purposes unless you can constrain a delegate to only accept "local" functions. -Craig
Apr 04 2008