I had a very simple method that would read a text file, parse it and create a lexicon of the type string[string].

public void loadLexicon(ref string[string] lex, string src)

It was high time I made the method more sophisticated and flexible (allowing for comments in the source file, checking for formatting errors etc). Because neither the comment bit (C-style line comments "//") nor the formatting check are too demanding I decided to do it in the existing loop that looked something like:

while (file.readln(buf)) {
  line = to!string(buf);
  // Do something with line
}

Soon, very soon indeed, I ran into all the problems associated with loops, which basically boils down to "Where the f.. am I now?". So I said to myself that component programming was the perfect fit for this kind of problem. I rearranged the program and now I have one line in the function that does the job:

public void loadLexicon(ref string[string] lex, string src) {
  // ...
// arr is of type string[] and holds the lines of the source file.
  auto dictionary = Lexicon(); // The output range
  lex = arr.byCommentFilter().byEntry().copy(dictionary).lexicon;
}

It's very nice indeed. The beauty of it is not only that I now have a nice, sequentially ordered "one-liner", the outsourcing of checks and filters freed my head from the loop logic, which helped me to focus on the respective algorithms. This lead to a leaner and cleaner implementation of each algorithm, because there are no dependecies on loop conditions or the position in the loop.

I could easily remove the comment filter, if the deployment version of the program ships with tidied up source files, or I could add a new component if necessary. In a loop, however trivial it may appear at first glance, it would not be so simple to add or remove parts of the logic.

One drawback is, that using ranges creates some overheads and code duplication. But the neatness of it is amazing, and I daresay that a lot of bugs are hidden in loops simply because the loop logic distracts and confuses the programmer and bugs finally find loopholes they can slip through.

Another drawback is that ranges demand a lot of boilerplate code. If properly implemented, there is a lot of code you have to write over and over again such as

if (isInputRange!Range && isInputRange!(ElementType!Range) &&
        is(ElementType!(ElementType!Range) == MyType))

I don't know if this could possibly be reduced. Or maybe it's just my lack of experience.

Reply via email to