Revised RFC on range design for D2
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Tue Sep 16 18:46:38 PDT 2008
Sergey Gromov wrote:
> Andrei Alexandrescu <SeeWebsiteForEmail at erdani.org> wrote:
>> Sergey Gromov wrote:
>>> Andrei Alexandrescu <SeeWebsiteForEmail at erdani.org> wrote:
>>>> Sergey Gromov wrote:
>>>>> Andrei Alexandrescu <SeeWebsiteForEmail at erdani.org> wrote:
>>>>>> Given that in D const is transitive, we can't operate with const the
>>>>>> same way C++ does. Consider something as trivial as a copy:
>>>>>>
>>>>>> Tgt copy(Src, Tgt)(Src src, Tgt tgt)
>>>>>> {
>>>>>> for (; !src.done; src.next) tgt.put(src.tip);
>>>>>> }
>>>>>>
>>>>>> Problem is, you won't be able to copy e.g. an int[][] to another because
>>>>>> the types aren't compatible.
>>>>> If Src is an input range you must make a deep copy. This holds true for
>>>>> your current design also. So this algorithm is flawed and it's good if
>>>>> it won't compile.
>>>> Great point. I need to sleep on this some more.
>>> Then I'll continue to think aloud.
>> [snip]
>>
>> Thanks for the code samples, they're cool. I hit a problem related to
>> the return type of head. Consider writing a range that iterates two
>> other ranges in lockstep. A very useful generic range. I started coding
>> it like this:
>>
>> struct Lockstep(R0, R1)
>> {
>> private R0 _r0;
>> private R1 _r1;
>> this(R0 r0, R1 r1)
>> {
>> _r0 = r0;
>> _r1 = r1;
>> }
>>
>> bool empty()
>> {
>> return _r0.empty || _r1.empty;
>> }
>>
>> Tuple!(ElementType!(R0), ElementType!(R1)) head()
>> {
>> return tuple(_r0.head, _r1.head);
>> }
>>
>> void next()
>> {
>> _r0.next;
>> _r1.next;
>> }
>> }
>
> Thinking aloud is fun. :P
>
> What you basically want to achieve is that
>
> Lockstep l1, l2;
> l1.head = l2.head;
>
> translates into
>
> l1._r0.head = l2._r0.head;
> l1._r1.head = l2._r1.head;
>
> all by itself. Umm... The simplest for a programmer would be compiler-
> supported multiple return values and multiple assignment:
>
> ref typeof(R0.head), ref typeof(R1.head) head()
> {
> return _r0.head, _r1.head;
> }
>
> then
>
> l1.head = l2.head
>
> is actually
>
> l1._r0.head, l1._r1.head = l2._r0.head, l2._r1.head;
>
> I'm not expecting this to be implemented though. Other methods,
> including returning a Tulpe!(), all return a struct. There's no use in
> returning references there, even if we could, as long as structs are
> bit-copied. All the tricks with reference fields rely substantially on
> the compiler performing specific actions on a per-field basis.
I figured a deceptively simple(r) solution. With apologies to Abba, I
let the code speak:
/**
Defines a range that moves two given ranges in lockstep.
*/
struct Lockstep(R0, R1)
{
struct ElementType
{
private R0 _r0;
private R1 _r1;
auto _0() { return _r0.head; }
auto _1() { return _r1.head; }
}
private ElementType _e;
this(R0 r0, R1 r1)
{
_e._r0 = r0;
_e._r1 = r1;
}
bool empty()
{
return _e._r0.empty || _e._r1.empty;
}
ref ElementType head()
{
return _e;
}
void next()
{
_e._r0.next;
_e._r1.next;
}
}
Now when I write:
Lockstep.(RA, RB) r;
auto x = r.head._0;
then I simply access whatever RA.head returns, be it by reference or
value. Problem solved.
Andrei
More information about the Digitalmars-d-announce
mailing list