September 12, 2008
Sergey Gromov wrote:
> Bill Baxter <wbaxter@gmail.com> wrote:
>> On Fri, Sep 12, 2008 at 11:58 PM, Sergey Gromov <snake.scaly@gmail.com> wrote:
>>>> So basically you changed
>>>> done ==> empty
>>>> head ==> tip
>>>> retreat ==> prev
>>>> ?
>>> The insight was about get/put ==> next.  That's the most significant
>>> change, others are merely renames as you rightfully point out.  Hence
>>> the "prev" which should mean both "get at the end" and "put to the end".
>> Ah ok.  Your switching to declaration syntax instead of usage syntax
>> confused me. :-)
>>
>> That is cute.  So
>>    r.put(e) ==> r.next = e
>> It would also mean the copy to output idiom would become
>>
>> for(; ! i.done; i.next)
>>    o.next = i.head;
>>
>> Would be cooler if it could be just while(!i.done) o.next = i.next;
>> .. oh well.
> 
> Exactly, I wanted it to be
> 
> while (!i.done)
>     o.next = i.next;

Hmm, let's see. So:

a) If i is an input range, then i.next returns by value.

b) If i is a forward range, then i.next returns by reference.

I assume that's what you had in mind?


Andrei
September 12, 2008
Ary Borenszweig wrote:
> Andrei Alexandrescu wrote:
>> In wake of the many excellent comments and suggestions made here, I made one more pass through the draft proposal for ranges.
>>
>> http://ssli.ee.washington.edu/~aalexand/d/tmp/std_range.html
>>
>> There are some comments in red illustrating some uncertainties (not all), and the names of the primitives have been updated. Bicycle shed galore! But don't forget to comment on the reactor as well :o).
>>
>>
>> Andrei
> 
> Two questions:
> - Is it possible to add elements to a range? Suppose a linked list, you want to traverse it's elements until a condition is met on an element, and then add something after it. Or before it. I see there's "put", but it also says "An output range models a one-pass forward writing iteration.", so I think it's not the same.

Never. Ranges never grow. You need access to the "mother" container, which will offer primitives for insertion and removal of elements.

> - The same question applies if you want to delete an element from a range.

Same.

> As for the names, I think it's impossible to find one-word names for the concepts you want to express. I always prefer expressive, easy to remember names instead of shorter but less meaningful names. Maybe:
> 
> head --> first
> toe --> last
> next --> moveFirst / dropFirst / skipFirst
> retreat -> moveLast / dropLast / skipLast
> done --> isEmpty (it's strange to think of a range as done)
> 
> So it's like dropFirst / dropLast shrink the range from either end, until it's empty.
> 
> Sorry if these things were already discussed, I didn't have time to read the hundreds of posts of the previous discussion, just some and the next proposal.

Yeah it's getting crazy.


Andrei
September 12, 2008
Sergey Gromov wrote:
> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> Sergey Gromov wrote:
>>> *)
>>> next() is specified to return a value, but reduce() is not.  This is probably a typo.  I'd prefer them both be implemented as (done(), head) and (reduce(), toe) respectively, but I don't know what your intention was.
>> Neither of next and retreat should return a value. In wake of constructors/destructors, we shouldn't return by-value lightly.
> 
> Then, in Input range primitives, e=r.next must be just r.next.

Oh, now I see. Fixed.

But I still want us to contemplate the possibility of unifying input ranges with recycling, and other ranges, under the same interface.


Andrei
September 12, 2008
Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Sergey Gromov wrote:
> > Bill Baxter <wbaxter@gmail.com> wrote:
> >> On Fri, Sep 12, 2008 at 11:58 PM, Sergey Gromov <snake.scaly@gmail.com> wrote:
> >>>> So basically you changed
> >>>> done ==> empty
> >>>> head ==> tip
> >>>> retreat ==> prev
> >>>> ?
> >>> The insight was about get/put ==> next.  That's the most significant change, others are merely renames as you rightfully point out.  Hence the "prev" which should mean both "get at the end" and "put to the end".
> >> Ah ok.  Your switching to declaration syntax instead of usage syntax confused me. :-)
> >>
> >> That is cute.  So
> >>    r.put(e) ==> r.next = e
> >> It would also mean the copy to output idiom would become
> >>
> >> for(; ! i.done; i.next)
> >>    o.next = i.head;
> >>
> >> Would be cooler if it could be just while(!i.done) o.next = i.next;
> >> .. oh well.
> > 
> > Exactly, I wanted it to be
> > 
> > while (!i.done)
> >     o.next = i.next;
> 
> Hmm, let's see. So:
> 
> a) If i is an input range, then i.next returns by value.
> 
> b) If i is a forward range, then i.next returns by reference.
> 
> I assume that's what you had in mind?

Not quite.

You cannot mutate an input range, it must be in specs.  Therefore it's up to the range designer what to return.  LineEater will return a const reference to an internal buffer.  RNG will return int.  Array will return a const reference to its element.  Some could return a new class instance every time.

If you want to mutate though, you require a forward range and use its i.first which must be a reference to the first element in the range. Then you can safely ignore the i.next result which will most likely be a reference to the previous i.first contents.
September 12, 2008
Sergey Gromov wrote:
> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> Sergey Gromov wrote:
>>> Bill Baxter <wbaxter@gmail.com> wrote:
>>>> On Fri, Sep 12, 2008 at 11:58 PM, Sergey Gromov <snake.scaly@gmail.com> wrote:
>>>>>> So basically you changed
>>>>>> done ==> empty
>>>>>> head ==> tip
>>>>>> retreat ==> prev
>>>>>> ?
>>>>> The insight was about get/put ==> next.  That's the most significant
>>>>> change, others are merely renames as you rightfully point out.  Hence
>>>>> the "prev" which should mean both "get at the end" and "put to the end".
>>>> Ah ok.  Your switching to declaration syntax instead of usage syntax
>>>> confused me. :-)
>>>>
>>>> That is cute.  So
>>>>    r.put(e) ==> r.next = e
>>>> It would also mean the copy to output idiom would become
>>>>
>>>> for(; ! i.done; i.next)
>>>>    o.next = i.head;
>>>>
>>>> Would be cooler if it could be just while(!i.done) o.next = i.next;
>>>> .. oh well.
>>> Exactly, I wanted it to be
>>>
>>> while (!i.done)
>>>     o.next = i.next;
>> Hmm, let's see. So:
>>
>> a) If i is an input range, then i.next returns by value.
>>
>> b) If i is a forward range, then i.next returns by reference.
>>
>> I assume that's what you had in mind?
> 
> Not quite.
> 
> You cannot mutate an input range, it must be in specs.  Therefore it's
> up to the range designer what to return.  LineEater will return a const reference to an internal buffer.  RNG will return int.  Array will return a const reference to its element.  Some could return a new class instance every time.

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 you want to mutate though, you require a forward range and use its i.first which must be a reference to the first element in the range.  Then you can safely ignore the i.next result which will most likely be a reference to the previous i.first contents.

This part does, I think, work.


Andrei
September 12, 2008
Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> Sergey Gromov wrote:
> > Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
> >> Sergey Gromov wrote:
> >>> Bill Baxter <wbaxter@gmail.com> wrote:
> >>>> On Fri, Sep 12, 2008 at 11:58 PM, Sergey Gromov <snake.scaly@gmail.com> wrote:
> >>>>>> So basically you changed
> >>>>>> done ==> empty
> >>>>>> head ==> tip
> >>>>>> retreat ==> prev
> >>>>>> ?
> >>>>> The insight was about get/put ==> next.  That's the most significant change, others are merely renames as you rightfully point out.  Hence the "prev" which should mean both "get at the end" and "put to the end".
> >>>> Ah ok.  Your switching to declaration syntax instead of usage syntax confused me. :-)
> >>>>
> >>>> That is cute.  So
> >>>>    r.put(e) ==> r.next = e
> >>>> It would also mean the copy to output idiom would become
> >>>>
> >>>> for(; ! i.done; i.next)
> >>>>    o.next = i.head;
> >>>>
> >>>> Would be cooler if it could be just while(!i.done) o.next = i.next;
> >>>> .. oh well.
> >>> Exactly, I wanted it to be
> >>>
> >>> while (!i.done)
> >>>     o.next = i.next;
> >> Hmm, let's see. So:
> >>
> >> a) If i is an input range, then i.next returns by value.
> >>
> >> b) If i is a forward range, then i.next returns by reference.
> >>
> >> I assume that's what you had in mind?
> > 
> > Not quite.
> > 
> > You cannot mutate an input range, it must be in specs.  Therefore it's up to the range designer what to return.  LineEater will return a const reference to an internal buffer.  RNG will return int.  Array will return a const reference to its element.  Some could return a new class instance every time.
> 
> 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.

I don't know how to make a generic deep copy, but I believe your meta-fu is much stronger than mine, so I'll leave it to you.  ;)
September 12, 2008
Andrei Alexandrescu, el 12 de septiembre a las 09:39 me escribiste:
> Pablo Ripolles wrote:
> >What about "isDone"?
> 
> isDone is great, I just wanted to keep the one-word streak going. Let's see what everyone else says.

I much prefer done, because is shorter, and, well, maybe because I hate CamelCase too ;)

-- 
Leandro Lucarella (luca) | Blog colectivo: http://www.mazziblog.com.ar/blog/
----------------------------------------------------------------------------
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
----------------------------------------------------------------------------
Creativity is great but plagiarism is faster
September 12, 2008
Sergey Gromov wrote:
> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>> Sergey Gromov wrote:
>>> Andrei Alexandrescu <SeeWebsiteForEmail@erdani.org> wrote:
>>>> Sergey Gromov wrote:
>>>>> Bill Baxter <wbaxter@gmail.com> wrote:
>>>>>> On Fri, Sep 12, 2008 at 11:58 PM, Sergey Gromov <snake.scaly@gmail.com> wrote:
>>>>>>>> So basically you changed
>>>>>>>> done ==> empty
>>>>>>>> head ==> tip
>>>>>>>> retreat ==> prev
>>>>>>>> ?
>>>>>>> The insight was about get/put ==> next.  That's the most significant
>>>>>>> change, others are merely renames as you rightfully point out.  Hence
>>>>>>> the "prev" which should mean both "get at the end" and "put to the end".
>>>>>> Ah ok.  Your switching to declaration syntax instead of usage syntax
>>>>>> confused me. :-)
>>>>>>
>>>>>> That is cute.  So
>>>>>>    r.put(e) ==> r.next = e
>>>>>> It would also mean the copy to output idiom would become
>>>>>>
>>>>>> for(; ! i.done; i.next)
>>>>>>    o.next = i.head;
>>>>>>
>>>>>> Would be cooler if it could be just while(!i.done) o.next = i.next;
>>>>>> .. oh well.
>>>>> Exactly, I wanted it to be
>>>>>
>>>>> while (!i.done)
>>>>>     o.next = i.next;
>>>> Hmm, let's see. So:
>>>>
>>>> a) If i is an input range, then i.next returns by value.
>>>>
>>>> b) If i is a forward range, then i.next returns by reference.
>>>>
>>>> I assume that's what you had in mind?
>>> Not quite.
>>>
>>> You cannot mutate an input range, it must be in specs.  Therefore it's
>>> up to the range designer what to return.  LineEater will return a const reference to an internal buffer.  RNG will return int.  Array will return a const reference to its element.  Some could return a new class instance every time.
>> 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.

> I don't know how to make a generic deep copy, but I believe your meta-fu is much stronger than mine, so I'll leave it to you.  ;)

It is doable, and if not, Walter will make it so :o).


Andrei
September 12, 2008
Andrei Alexandrescu wrote:
> P.S. The more I think of it, the more I like "tip" of the range. Short, poignant, easy to remember. Not pressing the red button just yet.

When I see "x.tip", it makes me think of the verb ("a function that tips x over").

If I force myself to think of the noun-sense, "tip" is obviously at one of the limits of the range, but is it at the front or the back? I'd have to check the docs to remember.

--benji
September 12, 2008
Andrei Alexandrescu wrote:
> Consider iterating over an array of int[], specifically an int[][]. Then when you call r.head you see the current int[]. You can store it and use it a few steps later or even after the iteration is done for as long as the array is around.
> 
> Contrast that with iterating a file containing lines of integers. The file has a buffer of type int[]. Every time you call r.next, the file range reads a new line, parses the integers, and REFILLS the array with them. If if generated a new array every line, that would cause a great deal of allocations.

Gotcha. I understand now.

Thinking off the top of my head, though, is it actually necessary define input ranges as reusing the same array? Wouldn't a peephole optimizer get rid of those extra allocations anyhow?

--benji