www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ideas from the Chapel language

reply bearophile <bearophileHUGS lycos.com> writes:
The Cray Inc is designing the Chapel Language:
http://chapel.cs.washington.edu/
The following notes are from the specification V. 0.750:
http://chapel.cs.washington.edu/spec-0.750.pdf
I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:

- Chap. 5.4.2 page 13, ranges with "by stride".
- Chap. 5.5 page 18, if expression look more readable:
  var half = if (i % 2) then i/2 +1 else i/2;
  Instead of:
  auto half = (i % 2) ? i/2 +1 : i/2;
- Chap. 5.7, page 23, Iterators (they look like copied from Python)
- Chap. 5.8, page 23, file I/O, seems better (it looks like copied from Python)
- Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
- Chap. 11.9.1, 11.9.2 page 68, zipper/tensor iteration (partially copied from
Python)
- Chap. 17.5 page 96, Tuple Destructuring (looking like copied from Python)
- Chap. 18.1-18.5 page 99-103, stridable Ranges, Unbounded Range Literals,
RangeAssignment, Range methods, etc.
- Chap. 19, page 105, Domains seem interesting too (Chap. 19.9 is about
subdomains).
- Chap. 20, page 121, more on iterators.
- Chap. 22, page 131, forall, ordered forall, cobegin, coforall, serial, etc.
- Chap. 24.1, page 143, Reduction Expressions

Bye,
bearophile
Oct 03 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
bearophile Wrote:

 The Cray Inc is designing the Chapel Language:
 http://chapel.cs.washington.edu/
 The following notes are from the specification V. 0.750:
 http://chapel.cs.washington.edu/spec-0.750.pdf
 I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:
 
 - Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
swap is very useful especially in exception safe programming. I would like to see swap used as the default implementation of D's transfer constructor (and C++0x's forthcoming move constructor)
Oct 03 2007
next sibling parent Sean Kelly <sean f4.ca> writes:
Bruce Adams wrote:
 bearophile Wrote:
 
 The Cray Inc is designing the Chapel Language:
 http://chapel.cs.washington.edu/
 The following notes are from the specification V. 0.750:
 http://chapel.cs.washington.edu/spec-0.750.pdf
 I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:

 - Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
swap is very useful especially in exception safe programming.
Certainly. But how much of a need is there for swap in a reference-based language like D? I would think that most swaps would simply operate on references. Unless you're talking about structs, and structs do not have copy ctors so there is little risk of an exception. Sean
Oct 03 2007
prev sibling parent reply Derek Parnell <derek psych.ward> writes:
On Wed, 03 Oct 2007 14:53:57 -0400, Bruce Adams wrote:

 bearophile Wrote:
 
 The Cray Inc is designing the Chapel Language:
 http://chapel.cs.washington.edu/
 The following notes are from the specification V. 0.750:
 http://chapel.cs.washington.edu/spec-0.750.pdf
 I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:
 
 - Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
swap is very useful especially in exception safe programming. I would like to see swap used as the default implementation of D's transfer constructor (and C++0x's forthcoming move constructor)
Isn't a simple template such this sufficient? template swap(TYPE) { void swap(ref TYPE a, ref TYPE b) { synchronized { TYPE temp = a; a = b; b = temp; } } } -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Oct 03 2007
next sibling parent Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
Derek Parnell Wrote:

 On Wed, 03 Oct 2007 14:53:57 -0400, Bruce Adams wrote:
 
 bearophile Wrote:
 
 The Cray Inc is designing the Chapel Language:
 http://chapel.cs.washington.edu/
 The following notes are from the specification V. 0.750:
 http://chapel.cs.washington.edu/spec-0.750.pdf
 I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:
 
 - Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
swap is very useful especially in exception safe programming. I would like to see swap used as the default implementation of D's transfer constructor (and C++0x's forthcoming move constructor)
Isn't a simple template such this sufficient? template swap(TYPE) { void swap(ref TYPE a, ref TYPE b) { synchronized { TYPE temp = a; a = b; b = temp; } } } -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Most of the time it is. Sometimes swapping references is sufficient but sometimes you actually want real data to change. As the type gets bigger you start to prefer decomposing swap into swaps of individual members rather than 2 whole copes. Do you really want to copy 120Mb twice? Actually you should decomposing the swap from the outset if possible (second to swapping just references if possible obviously). Swaps also have to be atomic and never throw exceptions. A more advanced template might use tuples recursively to do this. I would want that in the standard library. Some hardware platforms may support swaps directly. In reversible computing (okay so no-one in the real world uses that - yet) it is a fundamental operation. Then it becomes a compiler decision how best to implement it. If it is used as the default implementation for transfer constructors this goes double. I suspect a standard library implementation is sufficient from the outset leaving it up to the compiler vendor to decide how clever he or she needs to be. It continues to suprise me that we don't prefer swap to destructive assignment more generally. Perhaps it feels less natural after years of the C way? Bruce.
Oct 03 2007
prev sibling parent reply Gregor Richards <Richards codu.org> writes:
Derek Parnell wrote:
 On Wed, 03 Oct 2007 14:53:57 -0400, Bruce Adams wrote:
 
 bearophile Wrote:

 The Cray Inc is designing the Chapel Language:
 http://chapel.cs.washington.edu/
 The following notes are from the specification V. 0.750:
 http://chapel.cs.washington.edu/spec-0.750.pdf
 I think it's rather cute, it looks like a cross between C++, Fortress and
Python. Here are few things I think can be interesting for D designers too:

 - Chap. 11.5 page 65, swap operator (useful but probably not enough to justify
a new operator)
swap is very useful especially in exception safe programming. I would like to see swap used as the default implementation of D's transfer constructor (and C++0x's forthcoming move constructor)
Isn't a simple template such this sufficient? template swap(TYPE) { void swap(ref TYPE a, ref TYPE b) { synchronized { TYPE temp = a; a = b; b = temp; } } }
For the ridiculously-insane: void swap(T)(ref T a, ref T b) { synchronized { // this should be some kind of static for ... for (size_t i = 0; i < (a.sizeof/size_t.sizeof); i++) { (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i]; (cast(size_t*) &b)[i] = (cast(size_t*) &a)[i] ^ (cast(size_t*) &b)[i]; (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i]; } } } Add some loop unrolling and that's more efficient than memcpy :P - Gregor Richards PS: /me <3 XOR swapping
Oct 03 2007
next sibling parent reply David Brown <dlang davidb.org> writes:
On Wed, Oct 03, 2007 at 06:25:08PM -0700, Gregor Richards wrote:

 For the ridiculously-insane:

 void swap(T)(ref T a, ref T b)
 {
     synchronized {
         // this should be some kind of static for ...
         for (size_t i = 0; i < (a.sizeof/size_t.sizeof); i++) {
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
             (cast(size_t*) &b)[i] = (cast(size_t*) &a)[i] ^ (cast(size_t*) 
 &b)[i];
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
         }
     }
 }

 Add some loop unrolling and that's more efficient than memcpy :P
And rather devestating if another thread causes a garbage collection. Doesn't the synchronized just lock this section of code, not the whole program? But, why would it be any more efficient than the inside of the loop just saying: size_t tmp = ((cast(size_t*) &a)[i]; ((cast(size_t*) &a)[i] = ((cast(size_t*) &b)[i]; ((cast(size_t*) &b)[i] = tmp; This does 2 reads and 2 writes. The xor version does 4 reads and 3 writes. How could it be faster? The xor trick really only helps you if you are one architecture where you don't have a register to spare. Shuffling through a register is going to be much faster than multiple reads and writes to memory. David
Oct 03 2007
parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
David Brown Wrote:

 On Wed, Oct 03, 2007 at 06:25:08PM -0700, Gregor Richards wrote:
 
 For the ridiculously-insane:

 void swap(T)(ref T a, ref T b)
 {
     synchronized {
         // this should be some kind of static for ...
         for (size_t i = 0; i < (a.sizeof/size_t.sizeof); i++) {
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
             (cast(size_t*) &b)[i] = (cast(size_t*) &a)[i] ^ (cast(size_t*) 
 &b)[i];
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
         }
     }
 }

 Add some loop unrolling and that's more efficient than memcpy :P
And rather devestating if another thread causes a garbage collection. Doesn't the synchronized just lock this section of code, not the whole program? But, why would it be any more efficient than the inside of the loop just saying: size_t tmp = ((cast(size_t*) &a)[i]; ((cast(size_t*) &a)[i] = ((cast(size_t*) &b)[i]; ((cast(size_t*) &b)[i] = tmp; This does 2 reads and 2 writes. The xor version does 4 reads and 3 writes. How could it be faster? The xor trick really only helps you if you are one architecture where you don't have a register to spare. Shuffling through a register is going to be much faster than multiple reads and writes to memory. David
I think this is very much implementation defined. If you are operating on a block of memory rather than data small enough to fit in a register you have to dereference memory anyway. And lets not forget platforms with some sort of exchange registers as a primative operation. Though, I dislike joining the army of people rushing to suggest adding more and more (often unnecessary) features to an already feature rich language, I think that it is implementation defined justifies it being a low level operator implemented by the compiler. Swap is primative enough to have an unambiguous meaning and unlikely to confuse noobs. I'd very much like to hear what a (the) compiler writer has to say on the subject (especially in light of transfer constructors). I wonder if Walter is reading? Regards, Bruce.
Oct 04 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Bruce Adams wrote:
 David Brown Wrote:
 
 On Wed, Oct 03, 2007 at 06:25:08PM -0700, Gregor Richards wrote:

 For the ridiculously-insane:

 void swap(T)(ref T a, ref T b)
 {
     synchronized {
         // this should be some kind of static for ...
         for (size_t i = 0; i < (a.sizeof/size_t.sizeof); i++) {
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
             (cast(size_t*) &b)[i] = (cast(size_t*) &a)[i] ^ (cast(size_t*) 
 &b)[i];
             (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
         }
     }
 }

 Add some loop unrolling and that's more efficient than memcpy :P
And rather devestating if another thread causes a garbage collection. Doesn't the synchronized just lock this section of code, not the whole program? But, why would it be any more efficient than the inside of the loop just saying: size_t tmp = ((cast(size_t*) &a)[i]; ((cast(size_t*) &a)[i] = ((cast(size_t*) &b)[i]; ((cast(size_t*) &b)[i] = tmp; This does 2 reads and 2 writes. The xor version does 4 reads and 3 writes. How could it be faster? The xor trick really only helps you if you are one architecture where you don't have a register to spare. Shuffling through a register is going to be much faster than multiple reads and writes to memory. David
I think this is very much implementation defined. If you are operating on a block of memory rather than data small enough to fit in a register you have to dereference memory anyway. And lets not forget platforms with some sort of exchange registers as a primative operation. Though, I dislike joining the army of people rushing to suggest adding more and more (often unnecessary) features to an already feature rich language, I think that it is implementation defined justifies it being a low level operator implemented by the compiler. Swap is primative enough to have an unambiguous meaning and unlikely to confuse noobs. I'd very much like to hear what a (the) compiler writer has to say on the subject (especially in light of transfer constructors). I wonder if Walter is reading? Regards, Bruce.
I find it hard to believe that a compiler couldn't recognize that this is a swap operation: tmp = a; a = b; b = tmp; If it's not harder than I think for some reason, then it's not really needed in the language. --bb
Oct 04 2007
parent reply Derek Parnell <derek psych.ward> writes:
On Thu, 04 Oct 2007 17:55:05 +0900, Bill Baxter wrote:

 I find it hard to believe that a compiler couldn't recognize that this 
 is a swap operation:
     tmp = a;
     a = b;
     b = tmp;
 
 If it's not harder than I think for some reason, then it's not really 
 needed in the language.
Maybe it could, but that's not the point of a programming language. A programming language is for people, not computers, to read. It is whole lot easy to recognise "swap(a,b)" or even "a<->b" as a swapping operation than three lines of code. -- Derek Parnell Melbourne, Australia skype: derek.j.parnell
Oct 04 2007
next sibling parent renoX <renosky free.fr> writes:
Derek Parnell a écrit :
 On Thu, 04 Oct 2007 17:55:05 +0900, Bill Baxter wrote:
 
 I find it hard to believe that a compiler couldn't recognize that this 
 is a swap operation:
     tmp = a;
     a = b;
     b = tmp;

 If it's not harder than I think for some reason, then it's not really 
 needed in the language.
Maybe it could, but that's not the point of a programming language. A programming language is for people, not computers, to read. It is whole lot easy to recognise "swap(a,b)" or even "a<->b" as a swapping operation than three lines of code.
Uh? If 'swap(a,b)' is ok, then you put swap as a function call, that the compiler inline, or as a macro if you want to be sure that it will be inlined. As for an operator, given that I don't remember the last time that I needed to swap variables, I would vote against it. renoX
Oct 04 2007
prev sibling parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Derek Parnell wrote:
 On Thu, 04 Oct 2007 17:55:05 +0900, Bill Baxter wrote:
 
 I find it hard to believe that a compiler couldn't recognize that this 
 is a swap operation:
     tmp = a;
     a = b;
     b = tmp;

 If it's not harder than I think for some reason, then it's not really 
 needed in the language.
Maybe it could, but that's not the point of a programming language. A programming language is for people, not computers, to read. It is whole lot easy to recognise "swap(a,b)" or even "a<->b" as a swapping operation than three lines of code.
Right, so you put those three lines in a template function called "swap". If the compiler can recognize that's exchanging the values of a and b, then there's no need for swap to be a compiler intrinsic. The plain old function is good enough. --bb
Oct 04 2007
prev sibling parent BCS <ao pathlink.com> writes:
Reply to Gregor,

 For the ridiculously-insane:
 
 void swap(T)(ref T a, ref T b)
 {
 synchronized {
 // this should be some kind of static for ...
 for (size_t i = 0; i < (a.sizeof/size_t.sizeof); i++) {
 (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
 (cast(size_t*) &b)[i] = (cast(size_t*) &a)[i] ^
 (cast(size_t*) &b)[i];
 (cast(size_t*) &a)[i] ^= (cast(size_t*) &b)[i];
 }
 }
 }
 Add some loop unrolling and that's more efficient than memcpy :P
 
 - Gregor Richards
 
 PS: /me <3 XOR swapping
 
swap!(byte)(a, b) swap!(byte[5])(a, b)
Oct 03 2007