D-Programming-Language/phobos — pull request #861 by monarchdodra (2012-10-11 08:24:17+00:00)
Title: UFCS reduce

From the discussion: http://forum.dlang.org/thread/jorsc4$kvo$1@digitalmars.com

The development can be seen as being in 3 parts:

I. The first step was to get rid of that weird Args... interface reduce had going on, and replace it with explicit variables. From there, the implementation was split into 4 easy to call functions:

```D
auto reduceImpl(R)(R r) if (isInputRange!R) //Input range w/o seed

auto reduceImpl(R, S)(R r, S seed) if (isInputRange!R) //Input range w seed

auto reduceImpl(R)(R r) //opApply w/o seed
if (!isInputRange!R && isIterable!R)

auto reduceImpl(R, S)(R r, S seed) //opApply w seed
if (!isInputRange!R && isIterable!R)
```

This splice was mainly about splitting static ifs, and removing the now useless aliases. It is not possible to see it in the diff, but the only thing that went on here was code shuffling. Not a single new line of code was written during the splice.

II. The second step was the "public entry point" for the template itself, that will dispatch to the right function. Not much to see here actually.

III. The third step was a deprecation plan. I wrote an internal function called `reduceSwap`:

* While this function exists, both call scheme works.

* Once it is marked as deprecated, only the new scheme is legal.

The only new code are these two blocks:

```D
//Public entry points
auto reduce(R)(R r)
if (isIterable!R)
{
return reduceImpl(r);
}

auto reduce(U, V)(U u, V v)
if (isIterable!U || isIterable!V)
{
//Two arguments, is it reduce(R, S), or reduce(S, R)? What if both work?
//We try one, and if it fails, we simply call the other.
//Just in case there is some oddball usage where both work
//We default to the old behavior for now.

static if (is(typeof(reduceSwap(u, v)))) //Old behavior by default
//static if (is(typeof(reduceImpl(args[0], args[1])))) //New behavior by default
return reduceSwap(u, v); //Old behavior
else
return reduceImpl(u, v); //new behavior
}
```

```D
//Swapper: Transfroms a reduce(seed, r) into a reduce(r, seed)
//This is the function that needs to be marked deprecated.
auto reduceSwap(S, R)(S seed, R r)
{
return reduceImpl(r, seed);
}
```

This scheme is a bit complicated, but clean, and necessary. If and when we completely deprecate and remove the old call convention, it can be cleaned up.

AFAIK: This change CANNOT break existing code. The existing unittests were not changed a single line. They were also duplicated using the new call scheme. Both work.

Open to any feedback.