Ranges

bearophile bearophileHUGS at lycos.com
Thu Jun 18 18:00:08 PDT 2009


Steve Teale:

>I realize that some people with an IQ of 580 will find my questions naive and misguided - not to mention impertinent, but it seems to me that one of the responsibilities of being a leader is to explain to less gifted followers what the fuck is going on.<

If you read the book by Andrei you will probably find enough explanations. But we can also write a Wiki page (see at end of this post).

---------------------

Robert Fraser:

> I was just suggesting we need a better syntax, but I realized we have one: __traits(compiles).<

__traits() isn't a good looking syntax, and its semantic looks almost like a random conflation/accretion of too many different things (and some of them can be done better in other ways).

For example in my dlibs I have templates for the following purposes (and most of them are present in Tango too):
isAssociativeArray
isFloating
isIntegral
isStaticArray
isUnsigned

So instead of writing:
__traits(isStaticArray, x)

I write in D1:
IsStaticArray!(x)

In D2 you can write:
IsStaticArray!x

That looks better than the traits.
(The syntax of is() too looks like an accretion of mixed things).


>Why Andrei isn't using this is the real mystery.<

Maybe he agrees with me that __traits is not nice looking :-) Those underscores make it look like a temporary functionality.

is(typeof()) has purposes similar to __traits(compiles, ). Having two syntaxes to do the same thing may be bad.

Let's try using traits as you suggest. This it he original written by Steve Teale (copied from elsewhere):

template isInputRange(R) {
    enum bool isInputRange = is(typeof(
    {
        R r;              // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront;       // can invoke next
        auto h = r.front; // can get the front of the range
    }()));
}

This may be the traits version (there is no () after the {} after the "compiles"):

template isInputRange(R) {
    enum bool isInputRange = __traits(compiles, {
        R r;              // can define a range object
        if (r.empty) {}   // can test for empty
        r.popFront;       // can invoke next
        auto h = r.front; // can get the front of the range
    });
}

I don't know if this is correct, but if it's correct, is it better looking? It looks almost the same to me.

Both traits() and is() need a more clean and logic redesign, to move elsewhere some of their purposes, and to avoid duplication in their purposes.
Andrei has shown to be able to improve the API of the regex module, so maybe he can find a better design for is() and traits().

If types become first-class at compile time, of type "type", then you can remove some purposes from is() too, you can do:
type t1 = int;
type t2 = float;
static if (t1 != t2) {...

Instead of:
alias int t1;
alias float t2;
static if (!is(t1 == t2)) {...

--------------------------

Derek Parnell:

Thank you Derek Parnell for your nice summary about ranges: with to your post my understanding of this topic has gone from 10% to 15% :-)

There are things I don't understand from what you have written:

>OutputRange - This is an InputRange with the extra capability of being able to add elements to the range. In addition to the InputRange methods, it must also provide a method that adds a new element to the range, such that it becomes the current element. That method must be called 'put(E)' where 'E' is the new element.<

I guess a single linked list can be seen as an OutputRange then. You can add an item where you are and scan it forward (unfortunately linked listes today are dead, they are never an efficient solution on modern CPUs)
In what othr situations you may use/need an OutputRange? In a file, as in a stack, you can only add in a very specific point (the end, in files, or replace the current item). 


>ForwardRange - This is an InputRange with the extra capability of being able checkpoint the current first 'cursor' position simply by copying the range. When you copy an plain InputRange the copied range starts again from the absolute first element, but a copied ForwardRange starts at whatever was the current first element in the source range.<

I don't understand and I don't know what checkpointing may mean there.

I suggest to explain those things better, and then add 3 or more examples (very different from each other, complete, real-world and ready-to-be-copied-pasted-and-run, like you can find in every page of Borland Delphi documentation) for each kind of range. And then to put the page on the D Wiki :-)


>Now I admit that these are not method names I would have choosen, as I would have preferred names more like<

Andrei has shown that inventing very good names for those methods isn't easy...  And putting lot of uppercase letters in the middle of those names isn't nice, nor handy, and it's visually noisy.

Bye,
bearophile



More information about the Digitalmars-d mailing list