On Tuesday, 28 May 2013 at 17:24:13 UTC, H. S. Teoh wrote:
On Tue, May 28, 2013 at 11:37:06AM +0200, bearophile wrote:
Timothee Cour:

>python uses itertools.product which is lexicographic_depth. >Like you >say, no-one can agrees what the order should be, so let's >leave it up >to user through a template. Sounds like a no-brainer to me. >There
>are use cases for each order I mentioned.

Different cases enjoy different orderings, so giving it a
compile-time enum is OK. But I prefer the order of 9878 to be the default one, because it's the most commonly needed by me, and it's
what I expect when I port Python code to D.
[...]

OK, I'm looking at the code to see how this could be implemented, and it
seems to require some complications:

If both ranges are infinite, then the ordering needs to be Andrei's
suggested ordering (incremental 2D square). It *can* have other
orderings too, like diagonals, but that requires bidirectional ranges,
not just forward ranges.

If only one range is infinite, then it is allowed to be an input range, but that constrains it to a specific ordering (namely, finite range first, then increment infinite range). If the infinite range is more than an input range, then of course other orderings are possible, but explicitly supporting those cases seems to be a lot of work for very
little added value.

If both ranges are finite, then many different orderings are possible, but again it depends on the nature of the ranges. If one of them is an input range, then the other must be a forward range, and the order is
constrained.

The biggest problem here is, what should be the default ordering for the template? There is no single ordering that will work for every case.

Furthermore, how many different kinds of orderings should be supported? There are a lot of possibilities, even just in the finite case (if the ranges are both bidirectional, for example -- who's to say we should exclude a Peano-curve traversal of the cartesian product, or everything in between?). Even restricting ourselves to the simplest orderings, there's the question of how to efficiently implement something like Andrei's 2D traversal when you have two finite ranges of different
lengths.

Currently, I'm inclined to say, the library gets to decide on the ordering based on its inputs. I'd rather the template require minimal functionality from its input ranges and automatically decide on which ordering is best. I'd just follow bearophile's suggestion for the finite case -- the ordering in issue 9878 is certainly the most useful, and most likely expected (most uses of cartesian products would expect an ordering analogous to binary enumeration, I think). While adding an enum to specify the exact ordering is certainly possible, I'm not sure if
it's adding enough value to justify the complications in the
implementation.


T

I don't think the ordering should change just because the input type is changed, that would be very confusing, especially when code is just passing on ranges it's received from somewhere else.

The default should be the simplest ordering (across then down) and other orderings must be explicitly asked for. When an incompatible ordering (including using an infinite range for the "across" range with the default ordering) is being used it should show a helpful error message suggesting a compatible ordering.

There could also be an ordering constant "dontCare" which simply picks any ordering compatible with the nature of the input ranges. I don't think this should be the default because the common case is that you do care what the ordering is, you should have to explicitly say that you don't care.

It's also worth mentioning that the rules are more complicated than have been suggested - using an infinite range with the default ordering is fine as long as a finite range is used for the range that is being iterated over more quickly.

Reply via email to