While fiddling with this I came across something that seems odd in the behaviour of reduce and wondered if it's intended. It rather limits the usefulness of reduce with UFCS to "a + b" and "a - b".

Reduce works correctly when provided with a seed argument:

reduce!"a + b + 2"(0, [1,1,1]).writeln; // == 9 as expected

With UFCS I see no elegant way to reduce a chain with a more sophisticated reduce argument than the two simple ones listed above because the operation is not carried out on the first array element, used as the seed. This means:

[1,1,1].reduce!"a + b + 2".writeln; // == 7

which is useless and could easily trip people up because the intuitive expectation is that it will act like the seed example. If I am wrong in that expectation what is a use case for the seedless behaviour?

The fact that it does something different than the seeded version does not make the seedless version useless - in fact, that's what makes it useful. A typical use case is to find the maximum of a range (there is an example of this in the documentation at http://dlang.org/phobos/std_algorithm.html#reduce). If you don't know the highest possible value of elements, then you couldn't come up with an appropriate seed for this case.

I agree that the difference between the two versions of reduce can be a bit confusing. Maybe it would be better if they were named differently.

Is there a way of writing the operation to give the same answer as the seed answer?

In general, no (apart from the silly reduce!f(chain([seed], range))). If you want the behavior of the seeded version, use the seeded version.

The element in position 0 should surely have +2 added to itself, it's only being the seed out of convenience isn't it?

No, reduce!f(r) is not merely a syntactic sugar for reduce!f(0, r) (you could say it's a syntactic sugar for reduce!f(r.front, r.drop(1), though). Making reduce!f(r) be the same as reduce!f(0, r) doesn't really make any sense - would you expect [1, 2, 3].reduce!"a * b" to return 0? I wouldn't.

Instead we get 1 + (1 + 2) + (1 + 2). The order of reduce's arguments, (seed, range) prevent it being used with UFCS properly. If it were (range, seed) then there would be no problem:

[1,1,1].reduce!"a + b + 2"(0).writeln; // == 9

This would be better, yes. Reduce was written before there was UFCS, so they couldn't take this into account. I don't know if it is possible for this to be changed now, as it would definitely break some code.

Reply via email to