Thread overview
Array of byLineCopy ranges behaves as they are byLine
Mar 11, 2019
HaraldZealot
Mar 11, 2019
ag0aep6g
Mar 11, 2019
HaraldZealot
Mar 11, 2019
Paul Backus
March 11, 2019
Let assume I have multiple files (like "file1", "file2" and so on). I need to iterate them simultaneously with some logic. I have tried to create random access range of ranges, however, it behaves not as expected. Let "file1" is
```
1
2
3
4
```

Then this code
```d
File[] files;
foreach(filename; args[1 .. $])
{
    files ~= File(filename, "r");
}

auto ranges = files.map!(a => a.byLineCopy);

writeln(ranges[0].front);
writeln(ranges[0].front);
writeln(ranges[0].front);
```
produces
```
1
2
3
```
Even despite I'm using `byLineCopy`.

However, this code
```d
File[] files;
foreach(filename; args[1 .. $])
{
    files ~= File(filename, "r");
}

auto range = files[0].byLineCopy;

writeln(range.front);
writeln(range.front);
writeln(range.front);
```
produses
```
1
1
1
```
as expected.

What I'm doing wrong with `map`? Or is this a bug?

dmd v2.085.0

P.S. I know that I can call `dup` on `front` and I'm going to do so as workaround. However, I'm curious why current situation is taking place.
March 11, 2019
On Monday, 11 March 2019 at 15:23:53 UTC, HaraldZealot wrote:
> ```d
> File[] files;
> foreach(filename; args[1 .. $])
> {
>     files ~= File(filename, "r");
> }
>
> auto ranges = files.map!(a => a.byLineCopy);
>
> writeln(ranges[0].front);
> writeln(ranges[0].front);
> writeln(ranges[0].front);
> ```
> produces
> ```
> 1
> 2
> 3
> ```
[...]
> What I'm doing wrong with `map`? Or is this a bug?

`map` is lazy in the sense that it (re-)evaluates the given function whenever you access an element. That means you're calling `byLineCopy` three times on the same file. Your code effectively does this:

    writeln(files[0].byLineCopy.front);
    writeln(files[0].byLineCopy.front);
    writeln(files[0].byLineCopy.front);

The range created by `byLineCopy` immediately reads a line from the file to populate its `front`. So you're reading three lines from the file.

Strictly speaking, I don't think any of this qualifies as a bug. `map`'s behavior might be surprising, but it's deliberate, as far as I know.

To avoid the re-evaluation, assign `ranges[0]` to a variable before using it:

    auto lines = ranges[0];
    writeln(lines.front);
    writeln(lines.front);
    writeln(lines.front);

That should print the same line three times.
March 11, 2019
On Monday, 11 March 2019 at 17:04:56 UTC, ag0aep6g wrote:
>
> To avoid the re-evaluation, assign `ranges[0]` to a variable before using it:
>
>     auto lines = ranges[0];
>     writeln(lines.front);
>     writeln(lines.front);
>     writeln(lines.front);
>
> That should print the same line three times.

Ah yes, I forget about laziness of `map`. BTW, I have found other solution, which is more fit to my initial intention.

```d
ReturnType!(std.stdio.File.byLineCopy!(char, immutable(char)))[] ranges;
foreach(filename; args[1 .. $])
{
    ranges ~= File(filename, "r").byLineCopy;
}
```
March 11, 2019
On Monday, 11 March 2019 at 17:33:31 UTC, HaraldZealot wrote:
> Ah yes, I forget about laziness of `map`. BTW, I have found other solution, which is more fit to my initial intention.
>
> ```d
> ReturnType!(std.stdio.File.byLineCopy!(char, immutable(char)))[] ranges;
> foreach(filename; args[1 .. $])
> {
>     ranges ~= File(filename, "r").byLineCopy;
> }
> ```

An easier way to do this is to use the library function `std.array.array`:

auto ranges = args[1..$].map!(a => File(a, "r").byLineCopy).array;