May 22, 2014 DLang Front Page Code Example | ||||
---|---|---|---|---|
| ||||
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 Re: DLang Front Page Code Example | ||||
---|---|---|---|---|
| ||||
Posted in reply to Nicholas Londey | 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 |
Copyright © 1999-2021 by the D Language Foundation