Thread overview
Array of byLineCopy ranges behaves as they are byLine
Mar 11
ag0aep6g
March 11
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
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
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
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;