www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Phobos2: iota, ranges, foreach and more

reply bearophile <bearophileHUGS lycos.com> writes:
I am learning a bit more about ranges. They aren't hard to use for simple
things. Now I think I understand about 10% of this topic.

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

Can you tell me what is the name of the Phobos2 functioid that given a lazy
argument, iterates on it and returns the eager array of all its items? (it's
named array() in my libs and list() in Python).

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

Now I think iota() with just one argument is useful. When just one argument is
specified, then it's meant as the stop value, and the start value is meant to
be 0. This is handy, and it's the one used by range/xrange of Python.

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

While reading the source code of Phobos2 function calls like ".front" confuse
me, I find ".front()" more readable. I think I am not the only one to think
like this.

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

Into the source code of filter of algorithms I have seen something like:

ref SomeName opSlice() { return this; }

Recently Andrei has exmplained me:

People said, that sucks! With opApply I don't need to append the .all thingie!
So I told Walter to automatically call [] against the container. So people can
now write: [...] All the container has to to is define opSlice() to return its
"all" range.<

But if I comment out such ref opSlice() the Filter keeps working. What's the purpose of that operator inside Filter? (And I have to learn still about that usage of ref of the return). ------------------ Regarding the "popFront()" name, isn't a name like "next()" (for forward iteration) enough and nicer? (But see below too). ------------------ empty(), front(), etc are operators of struct/classes. So why not use the standard name syntax for D operators? popFront() => opNext() empty() ==> opEmpty front() ==> opFront() etc. ------------------ Is Phobos2 missing the groupby() of my dlibs (and Python itertools) still? I think this is a very important iterator. It simplifies lot of situations, because it represents a quite common idiom. In a few days I may become able to write it myself for D2 too. ------------------ D2 ranges don't yet support the index (and other values, there can be more than two!), as you can use with opApply. When the index is a simple integer, Python2.6 solves this simple indexing problem with the built-in "enumerate()" iterable that yields pairs (the starting point defaults to 0):
 s = "hello"
 for i, c in enumerate(s):



... 0 h 1 e 2 l 3 l 4 o
 for i, c in enumerate(s, 10):



... 10 h 11 e 12 l 13 l 14 o I don't see enumerate() yet in Phobos2, it may often be a cleaner solution. To solve the more general problem in D2, we can think about having more than one opFront(): opFront(), opFront2(), opFront3(), etc, that return Tuple!() with 1, 2, 3 arguments. And then the machinery of foreach can upack them: int opFront() { return this.current; } Tuple!(int, int) opFront2() { return tuple(count, this.current); } Tuple!(int, int, int) opFront3() { return tuple(count, 10, this.current); } foreach(x; Iter()) => calls opFront() foreach(x,y; Iter()) => calls opFront2() foreach(x,y,z; Iter()) => calls opFront3() etc. Then the front-end must guarantee to simplify away those temporary structs to remove the overhead. You can't have two different 2-len structs, because overload on the return value doesn't exists, so the following (doable with opApply) may be impossible with ranges, but I think this is an acceptable limitation: foreach(float x; Iter()) => calls one opFront() foreach(int y; Iter()) => calls another opFront() ------------------ After thinking about it I am unable to find a better design: I now think that your splitter() has to work like the xsplitter() of my dlibs (mine is specialized for strings, and this is good, because you often use it for them), that is like the str.split() method of Python strings, but lazy. The current design of splitter of Phobos2 is not good enough (beside the fact that it splits in a non intuitive way, but I think you have already fixed this in the next version of dmd). I'll probably ask again for this in future if you don't listen to this now, because as groupby() a splitter() is a very widely used operation. See also the rsplit(). You can find the semantics of split/rsplit here: http://docs.python.org/library/stdtypes.html#string-methods Playing Five minutes with the Python shell (or with the xsplit of my dlibs) may help you copy the semantics correctly (I use the word "copy" because copying that semantics, for a lazy range, is the best thing to do here). ------------------ I have done some simple experiments with ranges, I'll write about them in a future post. Bye, bearophile
May 04 2009
parent reply Georg Wrede <georg.wrede iki.fi> writes:
bearophile wrote:
 
 While reading the source code of Phobos2 function calls like ".front"
 confuse me, I find ".front()" more readable. I think I am not the
 only one to think like this.

The docs should be consistent and clear, also in trivial matters. If something is a function, then the parens should be there. The reader may know that you can omit the parens, but it has to be easy for him to recognize a name as a function.
May 04 2009
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
Georg Wrede wrote:
 bearophile wrote:
 While reading the source code of Phobos2 function calls like ".front"
 confuse me, I find ".front()" more readable. I think I am not the
 only one to think like this.

The docs should be consistent and clear, also in trivial matters. If something is a function, then the parens should be there. The reader may know that you can omit the parens, but it has to be easy for him to recognize a name as a function.

Omitting parens gives more options. For example, infinite ranges are defined and recognized as: enum bool empty = false; Andrei
May 04 2009
parent "Nick Sabalausky" <a a.a> writes:
"Andrei Alexandrescu" <SeeWebsiteForEmail erdani.org> wrote in message 
news:gto3np$2blr$1 digitalmars.com...
 Georg Wrede wrote:
 bearophile wrote:
 While reading the source code of Phobos2 function calls like ".front"
 confuse me, I find ".front()" more readable. I think I am not the
 only one to think like this.

The docs should be consistent and clear, also in trivial matters. If something is a function, then the parens should be there. The reader may know that you can omit the parens, but it has to be easy for him to recognize a name as a function.

Omitting parens gives more options. For example, infinite ranges are defined and recognized as: enum bool empty = false;

See, this is a good reason why "()" vs "no ()" should be dictated by the API, not the caller. Under the current system, there's nothing preventing someone from writing an "is this range empty?" check that seems to work on one range, but then fails to compile on any range that chooses to implement "empty" as in your example above.
May 04 2009