N.B. I haven't yet reviewed the proposal.

There's been a lot of discussion about the behavior of hash accumulators, and I've just have a chat with Walter about such.

There are two angles in the discussion:

1. One is, the hash accumulator should work as an operand in an accumulation expression. Then the reduce() algorithm can be used as follows:

HashAccumulator ha;
reduce!((a, b) => a + b)(ha, [1, 2, 3]);
writeln(ha.finish());

This assumes the hash overloads operator +.

2. The other is, the hash accumulator is an output range - a sink! - that supports put() for a lot of stuff. Then the code would go:

HashAccumulator ha;
copy([1, 2, 3], ha);
writeln(ha.finish());

I think (2) is a much more fertile view than (1) because the notion of "reduce" emphasizes the accumulation operation (such as "+"), and that is a forced notion for hashes (we're not really adding stuff there). In contrast, the notion that the hash accumulator is a sink is very natural: you just dump a lot of stuff into the accumulator, and then you call finish and you get its digest.

So, where does this leave us?

I think we should reify the notion of finish() as an optional method for output ranges. We define in std.range a free finish(r) function that does nothing if r does not define a finish() method, and invokes the method if r does define it.

Then people can call r.finish() for all output ranges no problem.

For files, finish() should close the file (or at least flush it - unclear on that). I also wonder whether there exists a better name than finish(), and how to handle cases in which e.g. you finish() an output range and then you put more stuff into it, or you finish() a range several times, etc.


Destroy!

Andrei

Reply via email to