RFC on range design for D2

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Wed Sep 10 15:08:29 PDT 2008


Sergey Gromov wrote:
> Steven Schveighoffer <schveiguy at yahoo.com> wrote:
>> "Andrei Alexandrescu" wrote
>>> Steven Schveighoffer wrote:
>>>> "Andrei Alexandrescu" wrote
>>>>> Notice that "a range can't grow" is different from "a range can't be 
>>>>> assigned from a larger range". In particular, a range operation can 
>>>>> return a range larger than both input ranges. But not larger than their 
>>>>> union :o).
>>>> Yes, so every time you add an element you have to update your forward 
>>>> range from the 'all' range so it includes the new element at the end. 
>>>> Every time you remove an element, you have to update your reverse range 
>>>> from the 'all' range so it excludes the element at the beginning. 
>>>> Failure to do this results in invalid ranges, which seems to me like a 
>>>> lot more work than simply not doing anything  (in the case of an 
>>>> iterator).  The pitfalls of using ranges for dynamically changing 
>>>> containers might outweigh the advantages that they provide in certain 
>>>> cases.
>>> No, this is incorrect. I don't "have to" at all. I could define the
>>> behavior of range as you mention, or I could render them undefined.
>>> Iterators invalidate anyway at the drop of a hat, so they're none the
>>> wiser. You can't transform a lack of an advantage into a disadvantage.
>> A range or iterator that becomes undefined when adding an element to a 
>> linked list or removing an element from a linked list (provided you don't 
>> remove the element in question) makes it useless for this type of purpose. 
>> What I want is a cursor that saves the position of an element, not the end 
>> and beginning.
>>
>> Here is what I'm assuming a range consists of, and granted this is an 
>> assumption since I didn't look at any of your implementation, and a list 
>> object which uses ranges doesn't even exist AFAIK.  Assume that integers 
>> below are individual elements
>>
>> all: 0 1 2 3 4 5 6 7 8 9 E
>> reverse range: 0 1 2 3 4
>> forward range: 5 6 7 8 9 E
>>
>> Now I remove an element from the front:
>>
>> all: 1 2 3 4 5 6 7 8 9 E
>> reverse range: ? 1 2 3 4
>> forward range: 5 6 7 8 9 E
>>
>> I've now lost my reverse iterator because it's no longer valid, but I can 
>> reconstruct it by diffing the forward iterator and list.all.
>>
>> If I add to the end I got a similar situation, I can reconstruct my forward 
>> iterator by diffing list.all and the reverse iterator.
> 
> You don't mention here which iterator usage pattern you are trying to 
> model with ranges.  I can think of at least two.
> 
> 1.  You use a single bidirectional 'center' iterator, center == 5.  As 
> one would naturally do with iterators.  Note then that whenever you use 
> your center for, say, backward iteration, you reconstruct the actual 
> range by calling list.begin.  You do it on each iteration.  No wonder it 
> stays valid even if you remove the first element in the meantime: you're 
> constructing your range from scratch anyway.  If you want to model this 
> pattern with ranges---no problem, keep an empty 'center' range, center 
> == (5,5), and reconstruct backward iteration range,
> 
> reverse = all.before(center);
> 
> whenever you need to iterate, then
> 
> center = reverse.end;
> 
> This 'center' range, being slightly less efficient, stays valid and 
> becomes invalid in exactly the same conditions as your classical 
> iterator.
> 
> 2.  You use 3 iterators, one for the list start, one for the center, and 
> one for the end.  In this case the 'start' iterator becomes invalid 
> after removing the first element exactly like 'reverse' range becomes 
> invalid in your example, with exactly the same consequences.

I'm acquiring the nagging feeling that Sergey understands ranges better 
than I do. I could understand how to address Steven's point only after 
reading the post above. Thanks, Sergey.

Andrei


More information about the Digitalmars-d-announce mailing list