dphobos

Using std.algorithm.iteration.sum with Duration[]


Why I can't use std.algorithm.iteration.sum with Duration[] ?

I thought I can use the sum in the same way than e.g. with int[]:

int[] ints = [40, 27, 5];
int intSum = ints.sum();
assert(intSum == 72);

But instead I get an unexpected (unexpected for me at least) compilation error:

/usr/include/dmd/phobos/std/algorithm/iteration.d(5885): Error: struct `core.time.Duration` member this is not accessible
so_002.d(11): Error: template instance `std.algorithm.iteration.sum!(Duration[])` error instantiating

I kind of understand the compilation error but I fail to understand why the limitation exists as for me there is nothing in documentation explaining this.

I have read:

Doesn't Duration[] conform with the constraints of sum:

auto sum(R)(R r)
if (isInputRange!R && !isInfinite!R && is(typeof(r.front + r.front)));

Or have I overlooked something else ?

The workaround is easy - use fold instead.

import std.algorithm : fold, sum;
import std.datetime : Duration, minutes;

void main()
{
  Duration[] durations = [40.minutes, 27.minutes, 5.minutes];

  // Unexpected compilation error:
  // /usr/include/dmd/phobos/std/algorithm/iteration.d(5885): Error: struct `core.time.Duration` member this is not accessible
  // so_002.d(11): Error: template instance `std.algorithm.iteration.sum!(Duration[])` error instantiating

  // auto durationSum = durations.sum();

  // fold works as expected
  Duration durationSum = durations.fold!((a, b) => a + b);
  assert(durationSum == 72.minutes);
}

Solution

  • The problem here is sum with zero arguments (except for the UFCS arg) tries to create a seed element of value zero, by calling the constructor Duration(0). While Duration(0) sorta makes sense, what is the value of Duration(1) - one minute? One second? One aeon? For this reason, Duration(0) simply doesn't compile. The reason why fold works is it always takes the first element as its seed. The drawback is it throws when the range it operates on is empty.

    Now, you may not care too much about that, and just want durations.sum() to work. Fret not - there's a way. You will have to pass the seed value to sum() as durations.sum(Duration.zero).

    Filed as a bug: https://issues.dlang.org/show_bug.cgi?id=19525