September 23, 2010
On Thu, 23 Sep 2010 16:43:13 -0400, Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:

> On 9/23/10 15:25 CDT, Don wrote:
>> Steven Schveighoffer wrote:
>>> On Thu, 23 Sep 2010 08:47:36 -0400, Robert Jacques <sandford@jhu.edu>
>>> wrote:
>>>
>>>> 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 :)
>>>
>>> The GC must be assumed to be pure even though it's not. Otherwise,
>>> pure functions can't do any heap allocation, and that makes them
>>> pretty useless in a garbage collected languages.
>>>
>>> In functional languages, allocating memory is usually considered pure.
>>
>> In the D spec, it already says that 'new' is considered pure.
>
> Which is wrong :o(. new invokes the constructor, which may do a variety of impure things.

Wouldn't they need to be pure constructors to be called in pure functions?

-Steve
September 23, 2010
	???

//weak, strong
int hello (const ref int x)
{

}

int main()
{
	immutable int a;
	int b;
	hello(a); //strong
	hello(b); //weak

}

	???


---

//impure
impure int hello()
{
	//globals
}
---

//impure
impure int hello(shared Myclass a)
{

}
---

//weak
int hello(MyClass a, immutable MyClass b)
{
	//noglobals,weak
}
---

//strong
int hello(const int a)
{
	//noglobals, weak
}
---

//strong
int hello( immutable MyClass a)
{
	//noglobals, weak
}


---
September 23, 2010
Don napisał:

> 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.

Good stuff. Separating restriction on globals and on parameters opens the door for compiler-enforced guarantees on a much wider range of cases.

> Note that this is possible only because immutable and const are transitive. It wouldn't be possible with head-const, or logical const.

But it would be possible with tail const. Quite a few functions could be made immutably pure if it meant tail immutability of their parameters. One example are manipulations of ranges on immutable structures.

> Transitive const gives us an absolutely huge win.

I can't agree more.

-- 
Tomek
September 23, 2010
On 2010-09-23 16:24:20 -0400, Tomek Sowiński <just@ask.me> said:

> Michel Fortin napisał:
> 
>> 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;
>> }
> 
> It's because popFront() can't be made pure. It could be if there was @tail immutable in the
> language -- pure functions would mark their arguments with @tail immutable instead of
> immutable. That allows popFront() to advance the range.

I know popFront() can't be made pure by the current rules. The proposal that started this thread is to relax 'pure' so that popFront() can be made pure. I was simply pointing a use case for that.

And to tell the truth, I have no idea where a tail-immutable qualifier would be helpful in this situation... could you elaborate?


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

September 23, 2010
Gary Whatmore napisał:

> 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.

As much as I'd like the new proposals, the focus and resources should be dead-on making D2 usable. Make a few stiches if necessary but it must be able to walk on its own, then carry the weight of industrial software development on its back.

Most of these proposals come up because people can write increasingly serious code in D. Before that these problems were never stumbled upon. Real production code will surely reveal new weakspots untractible in small grass-root projects and D creators and Phobos programmers will have to allocate time to address them. Surprisingly, it should make D3 better because we'll know what's wrong with D2. We don't really know that now.

-- 
Tomek
September 23, 2010
Michel Fortin napisał:

>> It's because popFront() can't be made pure. It could be if there was
>> @tail immutable in the
>> language -- pure functions would mark their arguments with @tail
>> immutable instead of
>> immutable. That allows popFront() to advance the range.
> 
> I know popFront() can't be made pure by the current rules. The proposal
> that started this thread is to relax 'pure' so that popFront() can be
> made pure. I was simply pointing a use case for that.
> 
> And to tell the truth, I have no idea where a tail-immutable qualifier would be helpful in this situation... could you elaborate?

I wrote that before I read Don's re-explanation that pure should just mean no globals (weak- pure) and it's to be able to call weak-pure functions from const-pure and immutable-pure functions that do impose restrictions on their parameters and offer guarantees about parallelizing, enable optimizations, etc. And that's cool.

So in the "three levels of purity" nomenclature, tail(const|immutable) would popularize the stronger two. E.g. popFront() could be immutably pure if the range in on an immutable collection and const-pure if it's on any collection.

-- 
Tomek
September 23, 2010
Thu, 23 Sep 2010 22:35:23 +0200, Tomek Sowiński wrote:

> dsimcha napisał:
> 
>> 1.  The documentation that says that the parameters need to be convertible to immutable is outdated.  This was changed a while ago to only requiring const.
> 
> Good to know. Yet, I wonder why such changes are not discussed on this NG and at the very least announced in the change log...

Just download the documentation of two subsequent versions and run gnu diff. It's that simple.
September 23, 2010
On Thu, 23 Sep 2010 10:05:45 -0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:

> On Wed, 22 Sep 2010 21:48:19 -0400, Robert Jacques <sandford@jhu.edu> wrote:
>
>> On Wed, 22 Sep 2010 13:10:36 -0400, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
>>
>>> On Wed, 22 Sep 2010 12:00:16 -0400, Robert Jacques <sandford@jhu.edu> wrote:
>>>> 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.
>
> Arrays are not value types.  A value type is one that contains no references, no matter how deep.  It is irrelevant if you have to spell out the references or not.

Arrays are implemented as a struct. And as per the language spec: (http://www.digitalmars.com/d/2.0/struct.html) all structs are value types *to the compiler*. This doesn't mean that logically, from the programmer's point of view, they aren't providing reference semantics.

> another example of something that is not a value type:
>
> alias int * iptr;
>
> foo(iptr p);
>
> iptr is not a value type just because you don't see any * in the signature.

*sigh* I explicitly referred to the type system/compiler. And to the type system iptr is a pointer, no matter what you call it.

>>>
>>> But the compiler will be able to tell.  I think adding a __traits(isStronglyPure, symbol) will be good for those rare occasions where you really want to ensure purity.
>>>
>>> static assert(__traits(isStronglyPure, foo));
>>>
>>> -Steve
>>
>> This would work, but it wouldn't be self-documenting, etc.
>
> Hm... OK, well I disagree, it looks like it's documented to me.  I don't see a difference between tagging something as strongly pure and putting in the static assert (except verbosity of course).  I will note that I think the above would be a rare situation.

To clarify, self-documenting => be able to automatically shows up in ddoc, etc.
September 23, 2010
On Thu, 23 Sep 2010 16:35:23 -0400, Tomek Sowiński <just@ask.me> wrote:
>
> On topic: this means a pure function can take a reference to data that can be mutated by
> someone else. So we're giving up on the "can parallelize with no dataraces" guarantee on
> pure functions?
>

In short, No. In long; the proposal is for pure functions become broken up into two groups (weak and strong) based on their function signatures. This division is internal to the compiler, and isn't expressed in the language in any way. Strongly-pure functions provide all the guarantees that pure does today and can be automatically parallelized or cached without consequence. Weakly-pure functions, don't provide either of these guarantees, but allow a much larger number of functions to be strongly-pure. In order to guarantee a function is strongly pure, one would have to declare all its inputs immutable or use an appropriate template constraint.
September 23, 2010
Tomek Sowiński napisał:

> So in the "three levels of purity" nomenclature, tail(const|immutable) would popularize the stronger two. E.g. popFront() could be immutably pure if the range in on an immutable collection and const-pure if it's on any collection.

Ehm, sorry.. popFront() is a bad example because 'this' is a reference. Tail const still would popularize the stronger pure, only it doesn't really buy you much. You can rebind argument pointers inside a strong-pure function, that's all.

(must stop posting at 1 a.m.)

-- 
Tomek