Just started looking at D, very promising!
One of the first programs I constructed involved infinite
sequences. A design question that showed up is whether to
construct the range as a struct/value, or class/reference. It
appears that structs/values are more the norm, but there are
exceptions, notably refRange. I'm wondering if there are any
community best practices or guidelines in this area.
One key difference is the behavior of take(). If the range is a
value/struct, take() does not consume elements. If it's a
ref/class, it does consume elements. From a consistency
perspective, it'd seem useful if the behavior was consistent as
much as possible.
Here's an example of the behavior differences below. It uses
refRange, but same behavior occurs if the range is created as a
class rather than a struct.
import std.range;
import std.algorithm;
void main() {
auto fib1 = recurrence!((a,n) => a[n-1] + a[n-2])(1, 1);
auto fib2 = recurrence!((a,n) => a[n-1] + a[n-2])(1, 1);
auto fib3 = refRange(&fib2);
// Struct/value based range - take() does not consume elements
assert(fib1.take(7).equal([1, 1, 2, 3, 5, 8, 13]));
assert(fib1.take(7).equal([1, 1, 2, 3, 5, 8, 13]));
fib1.popFrontN(7);
assert(fib1.take(7).equal([21, 34, 55, 89, 144, 233, 377]));
// Reference range (fib3) - take() consumes elements
assert(fib2.take(7).equal([1, 1, 2, 3, 5, 8, 13]));
assert(fib3.take(7).equal([1, 1, 2, 3, 5, 8, 13]));
assert(fib3.take(7).equal([21, 34, 55, 89, 144, 233, 377]));
assert(fib2.take(7).equal([610, 987, 1597, 2584, 4181, 6765,
10946]));
assert(fib2.take(7).equal([610, 987, 1597, 2584, 4181, 6765,
10946]));
}
--Jon