September 23, 2010
Jesse Phillips wrote:
> Walter Bright Wrote:
> 
>> Steven Schveighoffer wrote:
>>>> A pure function also cannot modify any data via its parameters. In other words, its parameters must be transitively const.
>>> Yes, a strongly pure function must have those traits.
>> No, that would be a weakly pure one.
>> 
>>> But, purity exists to allow for optimization.  A weakly pure function cannot be optimized anymore than a normal function, but a strongly pure can still be optimized even if it calls weakly-pure functions.
>>> 
>>> I'll give you an example (with a new keyword to help you understand the difference):
>>> 
>>> weaklypure void reverse(int[] x) { for(int i = 0; i * 2 < x.length; i++) swap(x[i], x[$-1-i]); }
>>> 
>>> pure int foo(const(int)[] x) { auto x2 = x.dup; reverse(x2); // do some
>>> calculation on x2 ... return calculation; }
>>> 
>>> Hopefully you can see how foo still is pure, while being able to call reverse.  Essentially, weakly-pure functions can be used to build strongly-pure functions.
>> This isn't what I was talking about - you didn't modify the contents of the
>>  array x[].
> 
> The problem is that you can't call reverse or sort unless the function is
> 'pure,' but the function can not be pure because it modifies its own
> parameters which means his example function cannot be marked pure even though
> it is.


The function in the example does not modify its parameters.
September 23, 2010
Jesse Phillips wrote:
> Steven Schveighoffer Wrote:
>> If we can define weakly pure functions this way, they most likely will be  way more common than unpure functions.  I know I avoid accessing global  variables in most of my functions.  Think about a range, almost all the  methods in a range can be weakly pure.  So that means you need to mark  every function as pure.

I think that's true. I/O is impure, but most other things are not.

>>
>> Would it not be less tedious to mark unpure functions instead of pure  functions?  Or am I just going too far with this?

You can use
pure:
at the top of the file.
The problem is that there's no syntax for impure, so it can't be used if you have a single impure function (which does logging, for example).
You can also wrap a bunch of functions in pure {}.

>> OR, maybe we could say, mark strongly pure functions as pure, mark  functions that access global data as something else (global?) and weakly  pure functions just aren't marked.
>>
>> -Steve
> 
> This is interesting, I'm not sure if either of these approaches could make it into D2, though a conservative approach was originally taken only because it was the most easy to prove.
> 
> I also find it interesting that D actually takes the 3-stage approach to several things. mutable, const, immutable; @safe, @trusted, @system. And this being unpure, contained, pure.
> 
> D recognizes the importance of these stages in other areas, so I feel it would be a miss if there is not a good reason the proposal doesn't work. Sadly what you learn from one of the stated areas (mutability, safety, purity) can't be applied to the other. But the pattern is there.

Interestingly, 'pure' is much simpler.

A weakly pure function can modify only the mutable parameters it was given. There's no need for a different language syntax for strongly pure, because it's just the case where the number of mutable parameters it was given are zero.

The point is that weakly pure and strongly pure are almost the same.

int weakfoo(ref int x) pure;

is exactly the same as strongly pure, except that it can also modify one single int, which you specify. Whereas

int impurefoo(int x);

could be doing _anything_.
September 23, 2010
Robert Jacques wrote:

>>>>>> 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'.
>>>>
>>>> Yes they can. They just need to declare the parameters to be immutable.
>>>
>>> What about value types?
>>
>> Value types are implicitly convertable to immutable, so they can be strongly-pure.
> 
> No their not. Remember, arrays and other structs are value types in the type system. Logically, they may be reference types, but as far as their type signature goes, they are value types.
> 
>> The problem I think Robert is referring to is, a person cannot always tell just from looking at a signature that a type is strongly-pure qualified or not.
> 
> And that you can not manually specify one or the other.

Yes you can. Just add const to the parameter declaration. This works because const is transitive.

> 
>> For example, is this function weak or strong?
>>
>> pure int foo(T t);

pure int foo(const T t);

is always strong pure, regardless of what T is.
September 23, 2010
Walter Bright wrote:
> Steven Schveighoffer wrote:
>>> A pure function also cannot modify any data via its parameters. In other words, its parameters must be transitively const.
>>
>> Yes, a strongly pure function must have those traits.
> 
> No, that would be a weakly pure one.

You're operating with a different definition. There are actually three levels. For extra clarity, let's split strongly-pure into two:

immutably pure == all parameters are immutable
const pure == all parameters are const
weakly pure == no access to globals

The interestingly thing is that an immutably pure function can safely call a weakly-pure function. The only things the weakly pure function will be able to change, are variables which are local to the immutably pure functions.

The *only* difference between weakly pure and immutably pure is the guarantees which are made about the parameters. And this is already covered by the const modifiers in the function signature. So that concept doesn't actually need to be part of pure.

Note that this is possible only because immutable and const are transitive. It wouldn't be possible with head-const, or logical const.
Transitive const gives us an absolutely huge win.
September 23, 2010
Don wrote:
> Walter Bright wrote:
>> Steven Schveighoffer wrote:
>>>> A pure function also cannot modify any data via its parameters. In other words, its parameters must be transitively const.
>>>
>>> Yes, a strongly pure function must have those traits.
>>
>> No, that would be a weakly pure one.
> 
> You're operating with a different definition. There are actually three levels. For extra clarity, let's split strongly-pure into two:
> 
> immutably pure == all parameters are immutable
> const pure == all parameters are const
> weakly pure == no access to globals
> 
> The interestingly thing is that an immutably pure function can safely call a weakly-pure function. The only things the weakly pure function will be able to change, are variables which are local to the immutably pure functions.

Ok, I see your point now. It's a good one.

> 
> The *only* difference between weakly pure and immutably pure is the guarantees which are made about the parameters. And this is already covered by the const modifiers in the function signature. So that concept doesn't actually need to be part of pure.
> 
> Note that this is possible only because immutable and const are transitive. It wouldn't be possible with head-const, or logical const.
> Transitive const gives us an absolutely huge win.
September 23, 2010
Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> Would it not be less tedious to mark unpure functions instead of pure functions?  Or am I just going too far with this?

You're probably going too far for it to be included in D2. D:

That said, I believe you are absolutely right, and what you're saying
is the right thing to do.

UP VOTES!!1

-- 
Simen
September 23, 2010
Simen kjaeraas Wrote:

> Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> 
> > Would it not be less tedious to mark unpure functions instead of pure functions?  Or am I just going too far with this?
> 
> You're probably going too far for it to be included in D2. D:
> 
> That said, I believe you are absolutely right, and what you're saying is the right thing to do.
> 
> UP VOTES!!1

We could use these proposals as a base for D 2.5 or D 3.0. Now that a better purity/constness system seems to solve problems more easily, D 2.0 seems too limited for modern systems programming. Is it finally time to put D 1.0 to rest, D 2.0 in maintenance mode, and concentrate on D 3? The TDPL book was finally published and D 2.0 has been in bugfix mode for a while. Once we have a 64-bit compiler ready, it would be time to move on.
September 23, 2010
On 23/09/2010 10:36 PM, Gary Whatmore wrote:
> Simen kjaeraas Wrote:
>
>> Steven Schveighoffer<schveiguy@yahoo.com>  wrote:
>>
>>> Would it not be less tedious to mark unpure functions instead of pure
>>> functions?  Or am I just going too far with this?
>>
>> You're probably going too far for it to be included in D2. D:
>>
>> That said, I believe you are absolutely right, and what you're saying
>> is the right thing to do.
>>
>> UP VOTES!!1
>
> We could use these proposals as a base for D 2.5 or D 3.0. Now that a better purity/constness system seems to solve problems more easily, D 2.0 seems too limited for modern systems programming. Is it finally time to put D 1.0 to rest, D 2.0 in maintenance mode, and concentrate on D 3? The TDPL book was finally published and D 2.0 has been in bugfix mode for a while. Once we have a 64-bit compiler ready, it would be time to move on.

Agreed. D 1.0 was a stem cell.  D 2.0 was part organ.  Time is of the
essence to evolve to a transplant-able product.

September 23, 2010
On Thu, 23 Sep 2010 02:57:28 -0400, Don <nospam@nospam.com> wrote:

> Robert Jacques wrote:
>
>>>>>>> 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'.
>>>>>
>>>>> Yes they can. They just need to declare the parameters to be immutable.
>>>>
>>>> What about value types?
>>>
>>> Value types are implicitly convertable to immutable, so they can be strongly-pure.
>>  No their not. Remember, arrays and other structs are value types in the type system. Logically, they may be reference types, but as far as their type signature goes, they are value types.
>>
>>> The problem I think Robert is referring to is, a person cannot always tell just from looking at a signature that a type is strongly-pure qualified or not.
>>  And that you can not manually specify one or the other.
>
> Yes you can. Just add const to the parameter declaration. This works because const is transitive.
>
>>
>>> For example, is this function weak or strong?
>>>
>>> pure int foo(T t);
>
> pure int foo(const T t);
>
> is always strong pure, regardless of what T is.

Don, this isn't always strong pure, regardless of what T is. Consider:

auto x = foo(t);
t.mutate;
auto y = foo(t);

The value of foo(t) can not be either cached nor parallelized.

I think what you meant was to just add immutable to the parameter declaration. i.e. pure int foo(immutable T t); And to answer my own question from earlier in the thread, this works because the automatic conversion of value types is done in a transitive manner. So if someone adds an indirection inside T, foo(t) will then fail to compile, because the implicit conversion of T to immutable(T) will fail. Having to specify all value-types as immutable is a bit annoying inside the function, as shadow variables would have to be used to make inputs mutable again, but this does satisfy the need to force a function signature to be strongly-pure.
September 23, 2010
On Thu, 23 Sep 2010 02:51:28 -0400, Don <nospam@nospam.com> wrote:

> Jesse Phillips wrote:
>> Steven Schveighoffer Wrote:
>>> If we can define weakly pure functions this way, they most likely will be  way more common than unpure functions.  I know I avoid accessing global  variables in most of my functions.  Think about a range, almost all the  methods in a range can be weakly pure.  So that means you need to mark  every function as pure.
>
> I think that's true. I/O is impure, but most other things are not.

The GC also impure :)