September 22, 2010
Don <nospam@nospam.com> wrote:

> Don wrote:
>> The docs currently state that:
>
>> PROPOSAL:
>> Drop the first requirement. Only one requirement is necessary:
>>  A pure function does not read or write any global mutable state.
>>
>
> Wow. It seems that not one person who has responded so far has understood this proposal! I'll try again. Under this proposal:
>
> If you see a function which has mutable parameters, but is marked as 'pure', you can only conclude that it doesn't use global variables. That's not much use on it's own. Let's call this a 'weakly-pure' function.
>
> However, if you see a function maked as 'pure', which also has only immutable parameters, you have the same guarantee which 'pure' gives us as the moment. Let's call this a 'strongly-pure' function.
>
> The benefit of the relaxed rule is that a strongly-pure function can call a weakly-pure functions, while remaining strongly-pure.
> This allows very many more functions to become strongly pure.
>
> The point of the proposal is *not* to provide the weak guarantee. It is to provide the strong guarantee in more situations.

And my axe!

That is, I support this.

-- 
Simen
September 22, 2010
On 9/22/10 4:21 AM, Don wrote:
> PROPOSAL:
> Drop the first requirement. Only one requirement is necessary:
>
> A pure function does not read or write any global mutable state.
>
> If a pure function has parameters that are all immutable or are
> implicitly convertible to immutable, then the compiler is permitted to
> cache the results.

I also support this proposal. In its current state, pure is pretty much useless, since you almost can't do anything serious with pure functions, let alone generic programming – it seems more like an excuse for not adding logic to determine whether a result can be cached to the optimizer than a true language feature…
September 22, 2010
On 2010-09-22 01:26:01 -0400, "Robert Jacques" <sandford@jhu.edu> said:

> So removing the concurrency safety from pure would greatly  expand the number of pure functions, however, automatic parallelism would  be lost.

Don clearly mentioned that this is not lost. Basically, for safe parallelism what you need is a function that has a) pure and b) no mutable reference parameter. Both are easily checkable at compile time, you'd just need to change your test for pure for a test that also checks the arguments.

The interesting thing with this change is that you can now call mutators functions on the local variables inside the pure function, because those can be made pure. You can't even iterate over a range inside a pure function without this!

	pure int test() {
		int result;
		auto r = iota(0, 10);
		while (!r.empty) {
			result += r;
			r.popFront(); // can't be pure by current rules!
		}
		return result;
	}

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

September 22, 2010
On 09/21/2010 10:47 PM, dsimcha wrote:
> 2.  If you mean that the parameters don't have to be const either, i.e. you can
> freely mutate state on the heap, i.e. of a ref parameter, or stuff that's
> reachable from a pointer or reference, then pure offers almost no useful guarantees.

Equal effects for equal inputs?

Andrei
September 22, 2010
I think you need to forbid access to shared state as well. It's possible to allow it if a strongly pure function calls a weakly pure function in an object that it created, but that seems unnecessarily complex. Actually, that makes me wonder: can constructors be marked pure?

Don Wrote:

> Don wrote:
> > The docs currently state that:
> 
> > PROPOSAL:
> > Drop the first requirement. Only one requirement is necessary:
> > 
> > A pure function does not read or write any global mutable state.
> > 
> 
> Wow. It seems that not one person who has responded so far has understood this proposal! I'll try again. Under this proposal:
> 
> If you see a function which has mutable parameters, but is marked as 'pure', you can only conclude that it doesn't use global variables. That's not much use on it's own. Let's call this a 'weakly-pure' function.
> 
> However, if you see a function maked as 'pure', which also has only immutable parameters, you have the same guarantee which 'pure' gives us as the moment. Let's call this a 'strongly-pure' function.
> 
> The benefit of the relaxed rule is that a strongly-pure function can
> call a weakly-pure functions, while remaining strongly-pure.
> This allows very many more functions to become strongly pure.
> 
> The point of the proposal is *not* to provide the weak guarantee. It is to provide the strong guarantee in more situations.

September 22, 2010
On Wed, 22 Sep 2010 04:13:34 -0400, Don <nospam@nospam.com> wrote:

> Don wrote:
>> The docs currently state that:
>
>> PROPOSAL:
>> Drop the first requirement. Only one requirement is necessary:
>>  A pure function does not read or write any global mutable state.
>>
>
> Wow. It seems that not one person who has responded so far has understood this proposal! I'll try again. Under this proposal:
>
> If you see a function which has mutable parameters, but is marked as 'pure', you can only conclude that it doesn't use global variables. That's not much use on it's own. Let's call this a 'weakly-pure' function.
>
> However, if you see a function maked as 'pure', which also has only immutable parameters, you have the same guarantee which 'pure' gives us as the moment. Let's call this a 'strongly-pure' function.
>
> The benefit of the relaxed rule is that a strongly-pure function can call a weakly-pure functions, while remaining strongly-pure.
> This allows very many more functions to become strongly pure.
>
> The point of the proposal is *not* to provide the weak guarantee. It is to provide the strong guarantee in more situations.

Yes, this in particular solves a problem I thought of a long time ago -- modularizing functions.

Let's say you have a function like this:

pure int foo()
{
  ulong[100] x;
  x[0] = 1;
  foreach(uint i; 1..x.length)
    x[i] = x[i-1] * i;
  ...
}

Let's say you have 10 pure functions that initialize x in the same way.  If you wanted to abstract the initialization of x, you could do:

void initX(ulong[] x)
{
  x[0] = 1;
  foreach(uint i; 1..x.length)
    x[i] = x[i-1] * i;
}

And then you just have:

pure int foo()
{
   ulong[100] x;
   initX(x);
   ...
}

But pure functions can only call pure functions, so we'd have to mark initX pure.  Your rules would allow this, and I think they are exactly what we need, I think you found the perfect rules to describe it.

-Steve
September 22, 2010
On Wed, 22 Sep 2010 09:16:37 -0400, Jason House <jason.james.house@gmail.com> wrote:

> I think you need to forbid access to shared state as well. It's possible to allow it if a strongly pure function calls a weakly pure function in an object that it created, but that seems unnecessarily complex.

Yes, I think Don expected that you shouldn't be allowed to access shared, but I don't think he specifically stated it.  I do think it needs to be added as a specific rule.

> Actually, that makes me wonder: can constructors be marked pure?

Of course!  A constructor just allocates memory and initializes it.  A pure constructor would not be allowed to access global or shared variables either.

-Steve
September 22, 2010
Steven Schveighoffer wrote:
> On Wed, 22 Sep 2010 09:16:37 -0400, Jason House <jason.james.house@gmail.com> wrote:
> 
>> I think you need to forbid access to shared state as well. It's possible to allow it if a strongly pure function calls a weakly pure function in an object that it created, but that seems unnecessarily complex.
> 
> Yes, I think Don expected that you shouldn't be allowed to access shared, but I don't think he specifically stated it.  I do think it needs to be added as a specific rule.

You're right, it should be explicitly stated.

> 
>> Actually, that makes me wonder: can constructors be marked pure?
> 
> Of course!  A constructor just allocates memory and initializes it.  A pure constructor would not be allowed to access global or shared variables either.
> 
> -Steve
September 22, 2010
On Wed, 22 Sep 2010 07:54:26 -0400, Michel Fortin <michel.fortin@michelf.com> wrote:

> On 2010-09-22 01:26:01 -0400, "Robert Jacques" <sandford@jhu.edu> said:
>
>> So removing the concurrency safety from pure would greatly  expand the number of pure functions, however, automatic parallelism would  be lost.
>
> Don clearly mentioned that this is not lost. Basically, for safe parallelism what you need is a function that has a) pure and b) no mutable reference parameter. Both are easily checkable at compile time, you'd just need to change your test for pure for a test that also checks the arguments.

What is lost is my ability to declare a function does x in the signature and for the compiler to check that. I really want to know if code monkey A changed some type's implementation to be thread unsafe, because detecting and tracking down a loss of performance due to loss of automatic parallelism is devilish.

> The interesting thing with this change is that you can now call mutators functions on the local variables inside the pure function, because those can be made pure. You can't even iterate over a range inside a pure function without this!
>
> 	pure int test() {
> 		int result;
> 		auto r = iota(0, 10);
> 		while (!r.empty) {
> 			result += r;
> 			r.popFront(); // can't be pure by current rules!
> 		}
> 		return result;
> 	}
>

I did mention this benefit in my post, but this example really shows just how awesome it really is. Which is why I think the concept of a simplified pure is so powerful and be included in the language. I just want it included in addition to the current pure concept.
September 22, 2010
On Wed, 22 Sep 2010 04:13:34 -0400, Don <nospam@nospam.com> wrote:

> Don wrote:
>> The docs currently state that:
>
>> PROPOSAL:
>> Drop the first requirement. Only one requirement is necessary:
>>  A pure function does not read or write any global mutable state.
>>
>
> Wow. It seems that not one person who has responded so far has understood this proposal! I'll try again. Under this proposal:

Funny, your re-iteration appears to coincided to my previous understanding. So either I've mis-understood twice, or I didn't sufficiently demonstrate my understanding when I made my critique. :) That said, I do think this version is much clearer and understandable.

> If you see a function which has mutable parameters, but is marked as 'pure', you can only conclude that it doesn't use global variables. That's not much use on it's own. Let's call this a 'weakly-pure' function.
>
> However, if you see a function maked as 'pure', which also has only immutable parameters, you have the same guarantee which 'pure' gives us as the moment. Let's call this a 'strongly-pure' function.
>
> The benefit of the relaxed rule is that a strongly-pure function can call a weakly-pure functions, while remaining strongly-pure.
> This allows very many more functions to become strongly pure.
>
> The point of the proposal is *not* to provide the weak guarantee. It is to provide the strong guarantee in more situations.

The problem from my point of view is that the programmer can not declare that a function should be 'strongly-pure' or 'weakly-pure'. Essentially, the point of the proposal is *to* provide the weak guarantee and leave the strong guarantee up to a sufficiently smart compiler. And I really don't want a function to suddenly run 8x slower, just because Joe-coder changed a type somewhere and made my 'strongly-pure' inner-loop 'weakly-pure'. That said, if we can only have one type of purity in the language, I think 'weakly-pure' is more powerful a concept than 'strongly-pure'.