RFC on range design for D2
Denis Koroskin
2korden at gmail.com
Tue Sep 9 06:28:48 PDT 2008
On Tue, 09 Sep 2008 04:37:41 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail at erdani.org> wrote:
> Denis Koroskin wrote:
>> 1) There is a typo:
>> // Copies a range to another
>> void copy(R1, R2)(R1 src, R2 tgt)
>> {
>> while (!src.isEmpty)
>> {
>> tgt.putNext(r.getNext); // should be tgt.putNext(src.getNext);
>> }
>> }
>
> Thanks! Fixed.
>
>> 2) R.next and R.pop could have better names. I mean, they represent
>> similar operations yet names are so different.
>
> I agree. Next was a natural choice. I stole pop from Perl. Any symmetric
> and short operation names would be welcome.
>
1) R.left += n / R.right -= n
2) R.left.advance(n) / R.right.advance(n) (or move)
3) R.advanceLeft(n)/R.advanceRight(n) (or moveLeft/moveRight)
>> 3) Walter mentioned that built-in array could be re-implemented using a
>> pair of pointers instead of ptr+length. Will it ever get a green light?
>> It fits range concept much better.
>
> Walter told me to first implement my design, and if it works, he'll do
> the change. Yes, it does fit ranges much better because the often-used
> next and, um, pop will only touch one word instead of two.
>
>> 4) We need some way of supporting dollar notation in user containers.
>> The hack of using __dollar is bad (although it works).
>
> It doesn't work for multiple dimensions. There should be an
> opDollar(uint dim) that gives the library information on which argument
> count it occured in. Consider:
>
> auto x = matrix[$-1, $-1];
>
> Here the dollar's occurrences have different meanings. A good start
> would be to expand the above into:
>
> auto x = matrix[matrix.opDollar(0)-1, matrix.opDollar(1)-1];
>
>> 5) I don't quite like names left and right! :) I think they should
>> represent limits (pointers to begin and end, in case of array) rather
>> that values. In this case, built-in arrays could be implemented as
>> follows:
>> struct Array(T)
>> {
>> T* left;
>> T* right;
>> size_t length() { return right-left; }
>> ref T opIndex(size_t index) { return left[index]; }
>> // etc
>> }
>> The rationale behind having access to range limits is to allow
>> operations on them. For example,
>> R.left-=n;
>
> I disagree. Defining operations on range limits opens a box that would
> make Pandora jealous:
>
> 1. What is the type of left in general? Um, let's define Iterator!(R)
> for each range R.
>
Yes, it should be iterator.
> 2. What are the primitives of an iterator? Well, -= sounds good. How do
> you check it for correctness? In fact, how do you check any operation of
> a naked iterator for correctness?
>
First of all, left is a forward iterator and right is a backward iterator.
That's why left might support ++, += and = while right support --, -= and
=.
Note that while we can rename ++ to advance() to get uniform naming.
In many cases it is desirable to store an iterator and set an iterator to
the range bounds.
> 3. I want to play with some data. What should I use here, ranges or
> iterators? ...
>
I don't think that ranges replace iterators (yet?). I define range as a
pair of iterators to myself.
For example, what is the equivalent D code of the following:
for (iterator it = ..., end = list.end(); it != end; ) {
if (predicate(*it)) {
it = listerase(it);
} else {
++it;
}
}
Range range = vector.all;
while (!range.isEmpty) {
if (predicate(range.left)) {
???
} else {
range.next;
}
}
Iterator solution would be as follows:
range.left = list.erase(range.left);
I took a list for the sake of simlicity, because erasing an element
doesn't update an end. However, in general, both left and right should be
updated. A good solution would be to return a new range, like this:
Range range = ...;
range = container.erase(???); // but what should be here?
maybe this:
container.erase(range); // erase the whole range, no need to return
anything because it would be empty anyway
container = container.eraseFirtsN(range, n); // erase first n elements
from a range, and return the rest.
container = container.eraseLastN(range, n); // the same but for other end
I don't say that iterators magically solve everyrthing, I merely try to
find problematic places.
> Much of the smarts of the range design is that it gets away WITHOUT
> having to answer embarrassing questions such as the above. Ranges are
> rock-solid, and part of them being rock-solid is that they expose enough
> primitives to be complete, but at the same time do not expose dangerous
> internals.
>
>> could be used instead of
>> foreach(i; 0..n) {
>> R.pop();
>> }
>> which is more efficient in many cases.
>
> Stop right there. That's not a primitive. It is an algorithm that gets
> implemented in terms of a primitive. I disagree that such an algorithm
> is an operator and does not have a name such as popN.
>
Okay, but you didn't mention popN() in the paper :)
>> Other that that - great, I like it.
>
> Thanks for your comments.
>
>
> Andrei
Thank YOU!
More information about the Digitalmars-d-announce
mailing list