Jump to page: 1 2
Thread overview
Ideas from the Chapel language
Oct 03, 2007
bearophile
Re: Ideas from the Chapel language (swap)
Oct 03, 2007
Bruce Adams
Oct 03, 2007
Sean Kelly
Oct 03, 2007
Derek Parnell
Oct 04, 2007
Bruce Adams
Oct 04, 2007
Gregor Richards
Oct 04, 2007
David Brown
Oct 04, 2007
Bruce Adams
Oct 04, 2007
Bill Baxter
Oct 04, 2007
Derek Parnell
Oct 04, 2007
renoX
Oct 04, 2007
Bill Baxter
Oct 04, 2007
BCS
October 03, 2007
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
October 03, 2007
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)

October 03, 2007
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
October 03, 2007
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
October 04, 2007
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.

October 04, 2007
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
October 04, 2007
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
October 04, 2007
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)


October 04, 2007
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.
October 04, 2007
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
« First   ‹ Prev
1 2