May 22, 2014
I was looking at this code the other day and thought to my self "This is terrible D" in the order of the C hello world with no error handling and returning a junk stack value.

I am a reasonably experienced C++ programmer but still a newbie at D. However, between the ideals of reusable code and no raw loops I felt there must be a better way.

 https://www.youtube.com/watch?v=cQkBOCo8UrE
 http://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning

So I tried rewriting the example on the dlang.org home page and came up with the following.

import std.algorithm, std.exception, std.stdio;

double average(T)(T range)
{
  enforce(!range.empty, "No inputs");

  auto totals = range.map!(a => tuple(1.0, cast(double)(a))).reduce!((a, b) => tuple(a[0] + b[0], a[1] + b[1]));
  return totals[1] / totals[0];
}

void main()
{
  writeln("Average line length: ", stdin.byLine.map!(a => a.length).average);
}


In doing so I ran into a few issues.
- Average or mean did not seem to already exist in algorithm or numeric.
- I could not think of an easy way to add component wise binaryOp to a Tuple.
- Tried using static array instead of tuple but could not work out how to crate a static array as the result of a lambda.
- Using dynamic array caused a compile issue and presumably would have had terrible heap garbage.

I am not necessarily saying we should replace the existing example but was curious what other people thought.
May 22, 2014
Nicholas Londey:

> So I tried rewriting the example on the dlang.org home page and came up with the following.
>
> import std.algorithm, std.exception, std.stdio;
>
> double average(T)(T range)
> {
>   enforce(!range.empty, "No inputs");
>
>   auto totals = range.map!(a => tuple(1.0, cast(double)(a))).reduce!((a, b) => tuple(a[0] + b[0], a[1] + b[1]));
>   return totals[1] / totals[0];
> }
>
> void main()
> {
>   writeln("Average line length: ", stdin.byLine.map!(a => a.length).average);
> }

This is a little better, but you can also use a reduce with two
functions:


import std.stdio, std.algorithm, std.exception, std.range;

real average(R)(R range) if (isInputRange!R) {
     enforce(!range.empty, "No inputs");

     immutable totals = range
                        .map!(x => tuple(real(x), 1L))
                        .reduce!((a, b) => tuple(a[0] + b[0], a[1]
+ b[1]));
     return totals[0] / real(totals[1]);
}

void main() {
     writeln("Average line length: ",
             stdin.byLine.map!walkLength.average);
}


But I think the Dsite has preferred the raw loop to show a
simpler D code that can be understood by not


> - Average or mean did not seem to already exist in algorithm or numeric.

It should be added.


> - I could not think of an easy way to add component wise binaryOp to a Tuple.

In theory you can define a new Tuple struct with "alias this" on
a Tuple, plus binaryOp +, but I don't know how well this could
work.


> - Tried using static array instead of tuple but could not work out how to crate a static array as the result of a lambda.

You need a slightly different syntax:

void main() {
     import std.stdio;

     auto myLambda = (int x) { int[2] a = x; return a; };
     myLambda(10).writeln;
}


But in your code it's not a good idea to keep the length in a
double value, and currently using the built-in array plus
operation on a fixed size array of length 2 is not efficient
because the D compilers perform a run-time call for that, and
they don't replace the tiny array with two inlined sums:
https://issues.dlang.org/show_bug.cgi?id=4240


> - Using dynamic array caused a compile issue and presumably would have had terrible heap garbage.

What compile issue? Real issues should go in Bugzilla.

Bye,
bearophile