On 2010-07-29 00:24, Dave Whipp wrote:
Aaron Sherman wrote:
On Wed, Jul 28, 2010 at 11:34 AM, Dave Whipp <d...@dave.whipp.name>
wrote:
To squint at this slightly, in the context that we already have
0...1e10 as
a sequence generator, perhaps the semantics of iterating a range
should be
unordered -- that is,
for 0..10 -> $x { ... }
is treated as
for (0...10).pick(*) -> $x { ... }
As others have pointed out, this has some problems. You can't
implement 0..*
that way, just for starters.
I'd say that' a point in may favor: it demonstrates the integers and
strings have similar problems. If you pick items from an infinite set
then every item you pick will have an infinite number of
digits/characters.
In smart-match context, "a".."b" includes "aardvark". It follows that,
unless you're filtering/shaping the sequence of generated items, then
almost every element ("a".."b").Seq starts with an infinite number of
"a"s.
Consistent semantics would make "a".."b" very not-useful when used as
a sequence: the user needs to say how they want to avoid the
infinities. Similarly (0..1).Seq should most likely return Real
numbers -- and thus (0..1).pick(*) can be approximated by
(0..1).pick(*, :replace), which is much easier to implement.
I agree that /in theory/ coercing from Range to Sequence, the new
Sequence should produce every possible value in the Range, unless you
specify an increment. You could argue that 0 and 1 in (0..1).Seq are
Ints, resulting in the expansion 0, 1, but that would leave a door open
for very nasty surprises.
In practise, producing every possible value in a Range with
over-countable items isn't useful and just opens the door for
inexperienced programmers to make perl run out of memory without ever
producing a warning, so I'd suggest that the conversion should fail
unless an increment is specified.
The general principle would be to avoid meaningless conversions, so (1
.. *).Seq ----> (1 .. *).pick should also just fail, but with finite
endpoints, it could succeed. The question here is whether we should open
for more parallelization at the cost of simplicity. I don't know.
So either you define some arbitrary semantics (what those should be
is, I think, the original topic of this thread) or else you punt
(error message). An error message has the advantage that you can
always do something useful, later.
I second that just doing something arbitrary where no actual definition
exists is a really bad idea. To be more specific, there should be no
.succ or .pred methods on Rat, Str, Real, Complex and anything else that
is over-countable. Trying to implement .succ on something like Str is
most likely dwimmy to a very narrow set of applications, but will
confuse everyone else.
Just to illustrate my point, if we have .succ on Str, why not have it on
Range or Seq?
Let's just play with that idea for a second - what would a reasonable
implementation of .succ on Range be?
(1 .. 10).succ --?--> (1 .. 11)
(1 .. 10).succ --?--> (2 .. 11)
(1 .. 10).succ --?--> (1 .. 12)
(1 .. 10).succ --?--> (10^ .. *)
Even starting a discussion about which implementation of .succ for Range
(above), Str, Rat or Real completely misses the point: there is no
definition of this function for those domains. It is non-existent and
trying to do something dwimmy is just confusing.
As a sidenote, ++ and .succ should be treated as two different things
(just like -- and .pred). ++ really means "add one" everywhere and can
be kept as such, where .succ means "the next, smallest possible item".
This means that we can keep ++ and -- for all numeric types.
Coercing to Sequence from Range should by default use .succ on the LHS,
whereas Seq could just use ++ semantics as often as desired. This would
make Ranges completely consistent and provide a clear distinction
between the two classes.
Getting back to 10..0
Yes, I agree with Jon that this should be an empty range. I don't care
what order you pick the elements from an empty range :).
Either empty, the same as 0 .. 10 or throw an error (I like errors :).
Regards,
Michael.