Hi Perl 6 people.
I've been looking closely at the definition of the Range class in S02
and the current Rakudo implementation, and I have some comments...
It seems that there are two intended uses for this class:
Range A pair of Ordered endpoints
Lets call the above the "interval definition".
The |..| operator now constructs a |Range| object rather than merely
functioning as an operator. Both sides are in item context.
Semantically, the |Range| acts like a list of its values to the extent
possible, but does so lazily, unlike Perl 5's eager range operator.
And this one the "list definition".
It seems fair enough to demand that a class supports both the concept of
being able to tell whether some value is between two endpoints (even
supporting open ranges) as well as being a lazy list in disguise, but
this concept only works on countable domains.
The most common example is 1 .. 100, which represents both an object
that can tell whether some other Integer is between 1 and 100
(inclusive) as well as the list of numbers from 1 to 100.
But there are problems if you try extending it to other data types that
model over-countable things, such as real numbers.
The Range 1.0001 .. 2.15 makes sense as an interval definition, but
there can hardly be a useful list definition without defining a step
size, at least, making it possible to use step sizes less than one.
This issue also surfaces when working with strings. As far as I can see,
Rakudo has some other comparison operation, which means that Ranges
using String endpoints are not dwimmy in the sense I'd expect:
say @("a" .. "ax").perl; # expands to a .. z, aa .. ax
say @("aa" .. "b").perl; # expands to the empty list
As far as I can see, the ordering is like so:
sub { $^a.chars cmp $^b.chars || $^a cmp $^b }
The code below shows that Rakudo does not currently use lexicographical
comparison, which may be surprising.
say 'aaa' cmp 'aa';
say 'aaa' cmp 'ba';
say 'aaa' ~~ 'aa' .. 'ba';
The output is:
1
-1
0
The last 0 should be 1 if using normal lexicographical ordering, just
like cmp does.
It is necessary to consider the data types that we want to use as
interval endpoints and carry out some sort of analysis of their domains.
The basic requirements are:
For the interval definition: there must be an obvious ordering relation,
so we can do $a cmp $b on any $a and $b of the given data type.
For the list definition: for any value $a of the given datatype, it must
be possible to come up with some $b, where no $c exists so $a < $c < $b.
Now for a short analysis of the different data types used as end points:
Integers - both interval and list definitions are ok.
Str - using lexicographical comparison permits only the interval
definition. Using the different comparison operator above permits both,
but results in counter-intuitive interval definition.
Num - using numerical comparison permits only the interval definition.
It should be easy to come up with a way to specify step sizes to support
list definition.
Complex - neither definitions are possible.
I am unsure about how this can be solved, apart from extracting the
interval definition to a super class to Range (we could call it an
Interval). The backside is that the class returned by the .. operator
depends on the operands:
Int .. Int -> Range
Str .. Str -> Interval
Complex .. Complex -> undef, exception or some other bad thing.
DataTypeA .. DataTypeB -> undef, exception or some other bad thing.
The most elegant solution would be if the data types themselves
indicated their capabilities. So if the given class has a cmp method
working on the same data type, the .. can construct an Interval. If the
given class has a next method (my name for a method returning the next
value), the .. can even construct a Range. If you want to construct an
Interval using non-countable things, you should then be able to provide
your own next replacement. Maybe like so:
my $range = 1.14 .. 1.82 :by {* + 0.01};
Another option is to provide a completely different operator for
constructing Intervals.
Darren Duncan brought this up before. See
http://osdir.com/ml/perl6-language/2009-02/msg00422.html
Regards,
Michael Zedeler.