join

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Tue Jan 18 11:25:55 PST 2011


I implemented a simple separatorless joiner as follows:

auto joiner(RoR)(RoR r)
if (isInputRange!RoR && isInputRange!(ElementType!RoR))
{
     static struct Result
     {
     private:
         RoR _items;
         ElementType!RoR _current;
         void prime()
         {
             for (;; _items.popFront())
             {
                 if (_items.empty) return;
                 if (!_items.front.empty) break;
             }
             _current = _items.front;
             _items.popFront();
         }
     public:
         this(RoR r)
         {
             _items = r;
             prime();
         }
         @property auto empty()
         {
             return _current.empty;
         }
         @property auto ref front()
         {
             assert(!empty);
             return _current.front;
         }
         void popFront()
         {
             assert(!_current.empty);
             _current.popFront();
             if (_current.empty) prime();
         }
         static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
         {
             @property auto save()
             {
                 Result copy;
                 copy._items = _items.save;
                 copy._current = _current.save;
                 return copy;
             }
         }
     }
     return Result(r);
}

The code has a few properties that I'd like to discuss a bit:

1. It doesn't provide bidirectional primitives, although it often could. 
The rationale is that implementing back and popBack incurs size and time 
overheads that are difficult to justify. Most of the time people just 
want to join stuff and go through it forward. The counterargument is 
that providing those primitives would make join more interesting and 
opens the door to other idioms. What say you?

2. joiner uses an idiom that I've experimented with in the past: it 
defines a local struct and returns it. As such, joiner's type is 
impossible to express without auto. I find that idiom interesting for 
many reasons, among which the simplest is that the code is terse, 
compact, and doesn't pollute the namespace. I'm thinking we should do 
the same for Appender - it doesn't make much sense to create an Appender 
except by calling the appender() function.

3. Walter, Don, kindly please fix ddoc so it works with auto. What used 
to be an annoyance becomes a disabler for the idiom above. Currently it 
is impossible to document joiner (aside from unsavory tricks).

4. I found the prime() idiom quite frequent when defining ranges. 
Essentially prime() positions the troops by the border. Both the 
constructor and popFront() call prime().

5. auto and auto ref rock - they allow simple, correct definitions.

6. Currently joiner() has a bug: it will not work as expected for 
certain ranges. Which ranges are those, and how can the bug be fixed?


Andrei


More information about the Digitalmars-d mailing list