On Fri, 04 Jun 2010 15:35:06 -0400, Graham Fawcett <[email protected]> wrote:

Hi folks,

I expected this program to print the lines of a file in reverse order:

    // bad.d
    import std.stdio;
    import std.range;
   void main() {
      auto f = File("bad.d");
      foreach(char[] line; retro(array(f.byLine())))
        writeln(line);
    }

...but instead it prints a jumble of line fragments. I suspect that
it's because byLine() is not dup'ing the arrays it's reading from the
file?

This version works:

    // good.d
    import std.stdio;
    import std.range;
   Retro!(char[][]) retroLines(File f) {
     char[][] lines;
      foreach(line; f.byLine())
        lines ~= line.dup;              // note the .dup!
      return retro(lines);
    }
   void main() {
      auto f = File("good.d");
      foreach(line; retroLines(f))
        writeln(line);
    }

..but if you remove the '.dup' then it prints a similar mess.

So, is there a bug in byLine(), or am I just using it wrong?

The latter. File is re-using the buffer for each line, so you are seeing the data get overwritten. This is for performance reasons. Not everyone wants incur heap allocations for every line of a file As you showed, it's possible to get the desired behavior if you need it. The reverse would be impossible.

Now, that being said, a nice addition would be to create a duper range that allows you to do one expression:

foreach(char[] line; retro(array(duper(f.byLine()))))

-Steve

Copied from my .announce reply :)

Reply via email to