Prettier iterator implementations in D?

Bill Baxter dnewsgroup at billbaxter.com
Fri Oct 20 00:50:31 PDT 2006


Alexander Panek wrote:
> I know Ruby, and it's loops are very cool, indeed. But this is D, and as
> a full blown *system and application programming language*, you can't
> compare it to Ruby. 

What is D if not "the speed of C++ with the ease of Ruby"?

> I don't think syntactic sugar should be added too
> hasty. 

I agree.  That's why plenty of discussion is needed.  So start poking holes!

> Apart from that I kinda like the delegate / function ptr syntax
> as it is.

And you could still use it as is if you like, because the suggestion is 
to make 'delegate' optional, not mandate it's removal.

About whether sugar is warranted here:  it seems Walter sees this 
delegate mechanism as becoming *the* primary technique for iteration in 
D.  That being the case, it should be as easy to read and write as 
possible.   Being easier to use than C++ iterators is the primary reason 
he gives for liking it, in fact.  So let's figure out how to make 
absolutely as simple as possible.

Right now, say you want to write a generic array iterator factory 
function 'traverser', which you do because it allows you to do this:

     foreach(int i; iarray.traverser()) {
       ...
     }
to iterate in some custom way over the elements of any array.

Here is the signature for that now (returns a delegate that takes a 
delegate parameter):

   int delegate(int delegate(inout typeof(ArrayT[0])))
      traverser(ArrayT)(inout ArrayT array)
   {
   }
   ...


The int delegate(int delegate ...) business is just too verbose to grok 
easily.   If I change the ints to voids and drop the 'delegate':

(( inout typeof(ArrayT[0]) )) reversed(ArrayT)(inout ArrayT array)

I think that's easier to look at if for no other reason than being 
shorter.  But I'll admit it probably is more mind boggling at first. 
But it's not a stretch to say most everybody could get used to reading

   (int) somefunc() {...}

as a function that returns a void-returning, int-taking delegate.  Just 
think of the (int) as a lone argument list ["takes an int"] and it's 
pretty clear.
And in that light it's not hard to see the extra sets of parens (( )) 
mean 'a void returning delegate that takes a void returning delegate'. 
At some point (( type )) just becomes second nature as the basic return 
signature for an iterator factory.  It's easy to see once you know to 
look for it, because its so short and (( )) stands out if spaced properly.

Another alternative is standard aliases for those complicated types:

template Types(ArgT) {
     static if( is (ArgT[0]) ) {
	alias typeof(ArgT[0]) elem_t;
     }
     else static if( is(ArgT.elem_t) ) {
	alias ArgT.elem_t elem_t;
     }
     else {
         alias ArgT elem_t;
     }
     alias int delegate(int delegate(inout elem_t)) iter_t;
     // this works for anything that is either array-like or has an
     // elem_t alias.
}

Then you can use those aliases like:

   Types!(ArrayT).iter_t  reversed(ArrayT)(inout ArrayT array)
   { ... }

that still looks kinda klunky :-/, but maybe better.  At least it's 
short enough to fit on one line.  But it just replaces having to know 
what (( )) means with having to know what Types!().iter_t means.  So I'm 
not sure it's really better.

Well at least it is something that works now!

--bb




More information about the Digitalmars-d mailing list