
Dear Dave, Do I correctly understand your opinion can be summarised as "for linear structures operator| is clearest; for complicated trees, function syntax; and combinations, a combination"? On Mon, 2009-03-02 at 10:01 -0500, David Abrahams wrote:
on Fri Feb 27 2009, Rogier van Dalen <rogiervd-AT-gmail.com> wrote:
To me, RangeEx provides functions that take a range and return a range. How is it not most natural to make these functions look like functions?
Every bit of runtime functionality is most naturally-expressed as a function call, according to some people. Those people end up writing code with lots and lots of parentheses, and they cite this uniformity as a source of expressiveness. Personally, I don't get it. If there's a more evocative syntax, we should consider using it.
You give a convincing argument. But is this different from ranges than for any expression? Taking the n-th power of a complicated expression is pow((... complicated expression ...), n) but might be more clearly expressed as (... complicated expression ...) #pow# n Shouldn't this go into a more general library? Shouldn't RangeEx by default offer the well-known syntax of function calls? (Even though I agree that also providing operator| is sensible, and not very hard at all.)
What we're doing with RangeEx (in general) only expresses a degenerate tree structure (i.e. a linear structure):
Is that true? I've used RangeEx-like facilities (that I wrote) mostly for more complicated trees, such as set operations.
What is wrong with saying "uniqued(rng)"? Why is it vital that the name has "make_ _range" to remind me that this returns a lazy range rather than a range?
I don't think "make_ _range" does anything to indicate laziness.
Sorry, I was trying (and clearly failed) to ask a Socratic question (echoing Neil's "I like the make_XXX_range because I instantly recognise that this creates a range adaptor"). We agree here.
Currently merge(), transform(), and the set algorithms use output iterators as a substitute for return values. Rephrasing them as functions would also get rid of output iterators, which would improve their interface.
While value semantics are wonderful, I have doubts that everything that operates on output iterators can be effectively reformulated to return a range without limiting expressiveness and efficiency.
Re efficiency, it would make sense to have copy (lazy_operation (rng), output_it) forward to the standard library operation. Re expressiveness, I am not sure what you mean. The output iterator versions of the operations I mention can be mimicked with "copy". I do know that I find that "merge()" returning ranges copy (merge (rng1, rng2) | transform (f), output_it); gives expressiveness than the implementation of the same using the standard library, which requires storing the intermediate values. To be fair, I have never compared performance, but I don't think the lazy range version is obviously slower. But maybe by "everything" you mean all possible operations, not just those currently in the standard library. In that case I'm sure you're right, but I don't see how that would make it undesirable to eliminate output iterators where possible, especially in a library that's bound to be used a lot. Cheers, Rogier