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.

Reply via email to