Author: larry
Date: Wed Mar 28 19:28:28 2007
New Revision: 14359
Modified:
doc/trunk/design/syn/S09.pod
Log:
User-definable array indexing hammered out by TheDamian++ and Dataweaver++
Modified: doc/trunk/design/syn/S09.pod
==============================================================================
--- doc/trunk/design/syn/S09.pod (original)
+++ doc/trunk/design/syn/S09.pod Wed Mar 28 19:28:28 2007
@@ -12,9 +12,9 @@
Maintainer: Larry Wall <[EMAIL PROTECTED]>
Date: 13 Sep 2004
- Last Modified: 14 Mar 2007
+ Last Modified: 28 Mar 2007
Number: 9
- Version: 18
+ Version: 19
=head1 Overview
@@ -146,6 +146,87 @@
buffer type. The unpacking is performed by coercion of such a buffer
type back to the type of the compact struct.
+=head1 Standard array indexing
+
+Standard array indices are specified using square brackets. Standard
+indices always start at zero in each dimension of the array (see
+L<"Multidimensional arrays">), and are always contiguous:
+
+ @dwarves[0] = "Happy"; # The 1st dwarf
+ @dwarves[6] = "Doc"; # The 7th dwarf
+
+ @seasons[0] = "Spring"; # The 1st season
+ @seasons[2] = "Autumn"|"Fall"; # The 3rd season
+
+
+=head1 Fixed-size arrays
+
+A basic array declaration like:
+
+ my @array;
+
+declares a one-dimensional array of indeterminate length. Such arrays
+are autoextending. For many purposes, though, it's useful to define
+array types of a particular size and shape that, instead of
+autoextending, fail if you try to access outside their
+declared dimensionality. Such arrays tend to be faster to allocate and
+access as well. (The language must, however, continue to protect you
+against overflow--these days, that's not just a reliability issue, but
+also a security issue.)
+
+To declare an array of fixed size, specify its maximum number of elements
+in square brackets immediately after its name:
+
+ my @dwarves[7]; # Valid indices are 0..6
+
+ my @seasons[4]; # Valid indices are 0..4
+
+No intervening whitespace is permitted between the name and the size
+specification, but "unspace" is allowed:
+
+ my @values[10]; # Okay
+ my @keys [10]; # Error
+ my @keys\ [10]; # Okay
+
+Note that the square brackets are a compile-time declarator, not a run-time
+operator, so you can't use the "dotted" form either:
+
+ my @values.[10]; # Error
+ my @keys\ .[10]; # Error
+
+Attempting to access an index outside a array's defined range will fail:
+
+ @dwarves[7] = 'Sneaky'; # Fails with "invalid index" exception
+
+It's also possible to explicitly specify a normal autoextending array:
+
+ my @vices[*]; # Length is: "whatever"
+ # Valid indices are 0..*
+
+=head1 Typed arrays
+
+The type of value stored in each element of the array (normally C<Any>)
+can be explicitly specified too, as an external C<of> type:
+
+ my num @nums; # Each element stores a native number
+ my @nums of num; # Same
+
+ my Book @library[1_000_000]; # Each element stores a Book object
+ my @library[1_000_000] of Book; # Same
+
+Alternatively, the element storage type may be specified as part of the
+dimension specifier (much like a subroutine definition):
+
+ my @nums[-->num];
+
+ my @library[1_000_000 --> Book];
+
+Arrays may also be defined with a mixture of fixed and autoextending
+dimensions:
+
+ my @calendar[12;*;24]; # "Month" dimension unlimited
+
+
=head1 Compact arrays
In declarations of the form:
@@ -166,6 +247,10 @@
hard to make these elements look like objects when you treat them
like objects--this is called autoboxing.)
+Such arrays are autoextending just like ordinary Perl arrays
+(at the price of occasionally copying the block of data to another
+memory location, or using a tree structure).
+
A compact array is for most purposes interchangeable with the
corresponding buffer type. For example, apart from the sigil,
these are equivalent declarations:
@@ -204,33 +289,45 @@
known encoding. Otherwise you must encode them explicitly from the
higher-level abstraction into some buffer type.)
+
=head1 Multidimensional arrays
-The declarations above declare one-dimensional arrays of indeterminate
-length. Such arrays are autoextending just like ordinary Perl arrays
-(at the price of occasionally copying the block of data to another
-memory location, or using a tree structure). For many purposes,
-though, it's useful to define array types of a particular size and
-shape that, instead of autoextending, throw an exception if you try
-to access outside their declared dimensionality. Such arrays tend
-to be faster to allocate and access as well. (The language must,
-however, continue to protect you against overflow--these days, that's
-not just a reliability issue, but also a security issue.)
+Perl 6 arrays are not restricted to being one-dimensional (that's simply
+the default). To declare a multidimensional array, you specify it with a
+semicolon-separated list of dimension lengths:
+
+ my int @ints[4;2]; # Valid indices are 0..3 ; 0..1
+
+ my @calendar[12;31;24]; # Valid indices are 0..11 ; 0..30 ; 0..23
+
+You can pass a multislice for the shape as well:
+
+ @@shape = (4;2);
+ my int @ints[ [;[EMAIL PROTECTED] ];
+ my int @ints[@@shape]; # Same thing
+
+Again, the C<[;]> list operator interpolates a list into a semicolon
+list.
+
+The shape may be supplied entirely by the object at run-time:
+
+ my num @nums = Array of num.new(:shape(3;3;3));
+ my num @nums .=new():shape(3;3;3); # same thing
A multidimensional array is indexed by a semicolon list, which is really
-a list of feeds in disguise. Each sublist is a slice/feed of one particular
-dimension. So
+a list of feeds in disguise. Each sublist is a slice/feed of one
+particular dimension. So:
@array[0..10; 42; @x]
-is really short for
+is really short for:
@array.postcircumfix:<[ ]>( <== 0..10 <== 42 <== @x );
The compiler is free to optimize to something faster when it is known
that lazy multidimensional subscripts are not necessary.
-Note that
+Note that:
@[EMAIL PROTECTED],@y]
@@ -261,122 +358,359 @@
distinct dimensions:
my @@x;
- @@x <== %hash.keys.grep: {/^X/};
+ @@x <== %hash.keys.grep: {/^\d+$/};
@@x <== =<>;
@@x <== 1..*;
@@x <== gather { loop { take rand 100 } };
- %hash{@@x}
+ @array{@@x}
-Conjecture, since @@x and @x are really the same object, any array can
+Conjecture: since @@x and @x are really the same object, any array can
keep track of its dimensionality, and it only matters how you use it
in contexts that care about the dimensionality:
my @x;
- @x <== %hash.keys.grep: {/^X/};
+ @x <== %hash.keys.grep: {/^\d+$/};
@x <== =<>;
@x <== 1..*;
@x <== gather { loop { take rand 100 } };
- %hash{@@x} # multidimensional
- [EMAIL PROTECTED] # flattened
+ @array{@@x} # multidimensional
+ @[EMAIL PROTECTED] # flattened
-To declare a multidimensional array, you may declare it with a signature as
-if it were a function returning I<one> of its entries:
+=head2 Autoextending multidimensional arrays
- my num @nums (Int); # one dimension, @nums[Int]
+Any dimension of the array may be specified as "C<*>", in which case
+that dimension will autoextend. Typically this would be used in the
+final dimension to make a ragged array functionally equivalent to an
+array of arrays:
-or alternately:
+ my int @ints[42; *]; # Second dimension unlimited
+ push(@ints[41], getsomeints());
- my @nums (Int --> num); # one dimension, @nums[Int]
+but I<any> dimensional of an array may be declared as autoextending:
-You can use ranges as types:
+ my @calendar[12;*;24]; # "Month" dimension unlimited
+ @calendar[1;42;8] = 'meeting' # See you on January 42nd
- my @nums (0..2 --> num); # one dimension, @nums[0..2]
- my @ints (0..3, 0..1 --> int); # one dimension, @ints[0..3; 0..1]
+It is also possible to specify that an array has an arbitrary number
+of dimensions, using a "hyperwhatever" (C<**>) at the end of the
+dimensional specification:
-That includes the "upto" range type:
+ my @grid[**]; # Any number of dimensions
+ my @spacetime[*;*;*;**]; # Three or more dimensions
+ my @coordinates[100;100;100;**]; # Three or more dimensions
- my @ints (^4, ^2 --> int); # one dimension, @ints[0..3; 0..1]
+Note that C<**> is a shorthand for C<[;] * xx *>, so the extra
+dimensions are all of arbitrary size. To specify an arbitrary number
+of fixed-size dimensions, write:
-You can pretend you're programming in Fortran, or awk:
+ my @coordinates[ [;] 100 xx * ];
- my int @ints (1..4, 1..2); # two dimensions, @ints[1..4; 1..2]
+This syntax is also convenient if you need to define a large number of
+consistently sized dimensions:
-Note that this only influences your view of the array in the current
-lexical scope, not the actual shape of the array. If you pass
-this array to another module, it will see it as having a shape
-of C<(0..3,0..1)> unless it also declares a variable to view it
-differently.
+ my @string_theory[ [;] 100 xx 11 ]; # 11-dimensional
-Alternately, you may declare it using a prototype subscript,
-but then you must remember to use semicolons instead of commas to
-separate dimensions, because each slice represents an enumeration of
-the possible values, so the following are all equivalent:
+=head1 User-defined array indexing
- my @ints (0..3, 0..1 --> int);
- my int @ints (0..3, 0..1);
- my int @ints[^4;^2];
- my int @ints[0..3; 0..1];
- my int @ints[0,1,2,3; 0,1];
+Any array may also be given a second set of user-defined indices, which
+need not be zero-based, monotonic, or even integers. Whereas standard array
+indices always start at zero, user-defined indices may start at any
+finite value of any enumerable type. Standard indices are always
+contiguous, but user-defined indices need only be distinct and in an
+enumerable sequence.
-You can pass a multislice for the shape as well:
+To define a set of user-defined indices, specify an explicit or
+enumerable list of the indices of each dimension (or the name of an
+enumerable type) in a set of curly braces immediately after the
+array name:
- @@fooshape = (0..3; 0..1);
- my int @ints[[;[EMAIL PROTECTED];
- my int @ints[@@fooshape]; # same thing
+ my @dwarves{ 1..7 };
+ my @seasons{ <Spring Summer Autumn Winter> };
-Again, the C<[;]> list operator interpolates a list into a semicolon
-list, which we do for consistency with subscript notation, not because
-it makes a great deal of sense to allow slices for dimensional specs
-(apart from ranges). So while the following is okay:
+ my enum Months
+ «:Jan(1) Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec»;
- my int @ints[0,1,2,3,4]; # same as 0..4
+ my @calendar{ Months; 1..31; 9..12,14..17 }; # Business hours only
-the following is a semantic error that the compiler should catch:
+Array look-ups via user-defined indices are likewise specified in curly
+braces instead of square brackets:
- my int @ints[^3,^3,^3]; # oops, comma instead of semicolon
+ @dwarves{7} = "Doc"; # The 7th dwarf
-The shape may be supplied entirely by the object at run-time:
+ say @calendar{Jan;13;10}; # Jan 13th, 10am
- my num @nums = Array of num.new(:shape(^3;^3;^3));
- my num @nums .=new():shape(^3;^3;^3); # same thing
+User-defined indices merely provide a second, non-standard "view" of the
+array; the underlying container remains the same. Each user-defined
+index in each dimension is mapped one-to-one back to the standard (zero-
+based) indices of that dimension. So, given the preceding definitions:
-Any dimension of the array may be specified as "C<Int>", in which case
-that dimension will autoextend. Typically this would be used in the
-final dimension to make a ragged array functionally equivalent to an
-array of arrays:
+ maps to
+ @dwarves{1} ------> @dwarves[0]
+ @dwarves{2} ------> @dwarves[1]
+ : :
+ @dwarves{7} ------> @dwarves[6]
- my int @ints[^42; Int];
- push(@ints[41], getsomeints());
+and:
+
+ maps to
+ @seasons{'Summer'} ------> @seasons[0]
+ @seasons{'Spring'} ------> @seasons[1]
+ @seasons{'Autumn'} ------> @seasons[2]
+ @seasons{'Winter'} ------> @seasons[3]
+
+ @seasons<Summer> ------> @seasons[0]
+ @seasons<Spring> ------> @seasons[1]
+ @seasons<Autumn> ------> @seasons[2]
+ @seasons<Winter> ------> @seasons[3]
+
+and:
+
+ maps to
+ @calendar{Jan;1;9} ------> @calendar[0;0;0]
+ @calendar{Jan;1;10} ------> @calendar[0;0;1]
+ : :
+ @calendar{Jan;1;12} ------> @calendar[0;0;3]
+ @calendar{Jan;1;14} ------> @calendar[0;0;4]
+ : :
+ @calendar{Feb;1;9} ------> @calendar[1;0;0]
+ : :
+ @calendar{Dec;31;17} ------> @calendar[11;30;7]
+
+User-defined indices can be open-ended, but only on the upper end (i.e.
+just like standard indices). That is, you can specify:
+
+ my @sins{7..*}; # Indices are: 7, 8, 9, etc.
+
+but not:
+
+ my @virtue{*..6};
+ my @koalas{*..*};
+ my @celebs{*};
+
+These last three are not allowed because there is no first index, and
+hence no way to map the infinity of negative user-defined indices back
+to the standard zero-based indexing scheme.
+
+Declaring a set of user-defined indices implicitly declares the array's
+standard indices as well (which are still zero-based in each dimension).
+Such arrays can be accessed using either notation. The standard indices
+provide an easy way of referring to "ordinal" positions, independent of
+user-specified indices:
+
+ say "The first sin was @sins[0]";
+ # First element, no matter what @sin's user-defined indexes are
+
+Note that if an array is defined with fixed indices (either standard or
+user-defined), any attempt to use an index that wasn't specified in the
+definition will fail. For example:
+
+ my @values{2,3,5,7,11}; # Also has standard indices: 0..4
+
+ say @values[-1]; # Fails (not a valid standard index)
+ say @values{1}; # Fails (not a valid user-defined index)
+
+ say @values{4}; # Fails (not a valid user-defined index)
+
+ say @values[5]; # Fails (not a valid standard index)
+ say @values{13}; # Fails (not a valid user-defined index)
-The shape may also be specified by types rather than sizes:
+Furthermore, if an array wasn't specified with user-defined indices,
+I<any> attempt to index it via C<.{}> will fail:
- my int @ints[Even; Odd];
+ my @dwarves[7]; # No user-defined indices;
-or by both:
+ say @dwarves{1}; # Fails: can't map .{1} to a standard .[] index
- my int @ints[0..100 where Even; 1..99 where Odd];
+When a C<:k>, C<:kv>, or C<:p> adverb is applied to a full array,
+the keys returned are always the standard indices.
-(presuming C<Even> and C<Odd> are types already constrained to be even or odd).
+ my @arr{1,3,5,7,9} = <one two three four five>;
-The C<Whatever> type will be taken to mean C<Int> within an array
-subscript, so you can also write:
+ say @arr:k; # 0, 1, 2, 3, 4
- my int @ints[^42; *];
+However, you can specify which set of keys are returned:
-Saying
+ say @arr:k[] # 0, 1, 2, 3, 4
+ say @arr:k{} # 1, 3, 5, 7, 9
- my int @ints[^42; **];
+When C<:k>, C<:kv>, or C<:p> is applied to an array slice, it returns
+the kind of indices that were used to produce the slice, unless the type
+of index is explicitly requested:
-would give you an array of indeterminate dimensionality.
+ @arr[0..2]:p # 0=>'one', 1=>'two', 2=>'three'
+ @arr[0..2]:p[] # 0=>'one', 1=>'two', 2=>'three'
+ @arr[0..2]:p{} # 1=>'one', 3=>'two', 5=>'three'
+
+ @arr{1,3,5}:p # 1=>'one', 3=>'two', 5=>'three'
+ @arr{1,3,5}:p[] # 0=>'one', 1=>'two', 2=>'three'
+ @arr{1,3,5}:p{} # 1=>'one', 3=>'two', 5=>'three'
+
+
+=head1 Inclusive subscripts
+
+Within any array look-up (whether via C<.[]> or C<.{}>), the "whatever
+star" can be used to indicate "all the indices". The meaning of
+"all" here depends on the definition of the array. If there are no
+pre-specified indices, the star means "all the indices of currently
+allocated elements":
+
+ my @data # No pre-specified indices
+ = 21, 43, 9, 11; # Four elements allocated
+ say @data[*]; # So same as: say @data[0..3]
+
+ @data[5] = 101; # Now six elements allocated
+ say @data[*]; # So same as: say @data[0..5]
+
+If the array is defined with predeclared fixed indices (either standard
+or user-defined), the star means "all the defined indices":
+
+ my @results{1..100 :by(2)} # Pre-specified indices
+ = 42, 86, 99, 1;
+
+ say @results[*]; # Same as: say @results[0..49]
+ say @results{*}; # Same as: say @results{1..100 :by(2)}
+
+You can omit unallocated elements, either by using the :v adverb:
+
+ say @results[*]:v; # Same as: say @results[0..3]
+ say @results{*}:v; # Same as: say @results{1,3,5,7}
+
+or by using a "zen slice":
+
+ say @results[]; # Same as: say @results[0..3]
+ say @results{}; # Same as: say @results{1,3,5,7}
+
+A "whatever star" can also be used as the starting-point of a range
+within a slice, in which case it means "from the first index":
+
+ say @calendar[*..5]; # Same as: say @calendar[0..5]
+ say @calendar{*..Jun}; # Same as: say @calendar{Jan..Jun}
+
+ say @data[*..3]; # Same as: say @data[0..3]
+
+As the end-point of a range, a lone "whatever" means "to the maximum
+specified index" (if fixed indices were defined):
+
+ say @calendar[5..*]; # Same as: say @calendar[5..11]
+ say @calendar{Jun..*}; # Same as: say @calendar{Jun..Dec}
+
+or "to the largest allocated index" (if there are no fixed indices):
+
+ say @data[1..*]; # Same as: say @results[1..5]
+
+=head1 Negative and differential subscripts
+
+The "whatever star" can also be treated as a number inside a
+standard index, in which case it evaluates to the length of the
+array. This provides a clean and consistent way to count back or
+forwards from the end of an array:
+
+ @array[*-$N] # $N-th element back from end of array
+ @array[*+$N] # $N-th element at or after end of array
+
+More specifically:
+
+ @array[*-2] # Second-last element of the array
+ @array[*-1] # Last element of the array
+ @array[+*] # First element after the end of the array
+ @array[*+0] # First element after the end of the array
+ @array[*+1] # Second element after the end of the array
+
+ @array[*-3..*-1] # Slice from third-last element to last element
+
+(Note that, if a particular array dimension has fixed indices, any
+attempt to index elements after the last defined index will fail.)
+
+Using a standard index less than zero prepends the corresponding number
+of elements to the start of the array and then maps the negative index
+back to zero:
+
+ @results[-1] = 42; # Same as: @results.unshift(42)
+
+ @dwarves[-2..-1] # Same as: @dwarves.unshift(<Groovy Sneaky>)
+ = <Groovy Sneaky>;
+
+Note that, as with a normal C<unshift>, the new elements are
+actually stored starting at standard index zero, after pre-existing
+elements have been bumped to the right. Hence after the assignments
+in the preceding example:
+
+ say @results[0]; # 42
+ say @dwarves[0]; # Groovy
+
+Using a negative index on an array of fixed size will fail if the
+resulting number of elements exceeds the defined size.
+
+Note that the behaviour of negative indices in Perl 6 is
+different to that in Perl 5:
+
+ # Perl 5...
+ ............_____________________________..................
+ : | | | | | | : :
+ .....:.....|_____|_____|_____|_____|_____|.....:.....:.....
+ [0] [1] [2] [3] [4] [5] [6] [7]
+ [-7] [-6] [-5] [-4] [-3] [-2] [-1]
+
+
+ # Perl 6...
+ ............_____________________________..................
+ : | | | | | | : :
+ .....:.....|_____|_____|_____|_____|_____|.....:.....:.....
+ [-2] [-1] [0] [1] [2] [3] [4] [5] [6] [7]
+ [*-7] [*-6] [*-5] [*-4] [*-3] [*-2] [*-1] [*+0] [*+1] [*+2]
+
+The Perl 6 semantics avoids indexing discontinuities (a source of subtle
+runtime errors), and provides ordinal access in both directions at both
+ends of the array.
+
+=head1 Mixing subscripts
+
+Occasionally it's convenient to be able to mix standard and user-defined
+indices in a single look-up.
+
+Within a C<.[]> indexing operation you can use C<*{$idx}> to
+convert a user-defined index C<$idx> to a standard index. That is:
+
+ my @lengths{ Months } = (31,28,31,30,31,30,31,31,30,31,30,31);
+
+ @lengths[ 2 .. *{Oct} ] # Same as: @lengths[ 2 .. 9 ]
+
+Similarly, within a C<.{}> indexing operation you can use C<*[$idx]>
+to convert from standard indices to user-defined:
+
+ @lengths{ *[2] .. Oct } # Same as: @lengths{ Jan .. Oct }
+
+In other words, when treated as an array within an indexing
+operation, C<*> allows you to convert between standard and
+user-defined indices, by acting like an array of the indices
+of the indexed array. This is especially useful for mixing
+standard and user-defined indices within multidimensional
+array look-ups:
+
+ # First three business hours of every day in December...
+ @calendar{Dec; *; *[0..2]}
+
+ # Last three business hours of first three days in July...
+ @calendar[*{July}; 0..2; *-3..*-1]
+
+Extending this feature, you can use C<**> within an indexing operation
+as if it were a multidimensional array of I<all> the indices of a fixed
+number of dimensions of the indexed array:
+
+ # Last three business hours of first three days in July...
+ @calendar{ July; **[0..2; *-3..*-1] }
+
+ # Same...
+ @calendar[ **{July; 1..3}; *-3..*-1]
=head1 PDL support
An array C<@array> can be tied to a PDL at declaration time:
my num @array[@@mytensorshape] is PDL;
- my @array is PDL(:shape(^2;^2;^2;^2)) of int8;
+ my @array is PDL(:shape(2;2;2;2)) of int8;
PDLs are allowed to assume a type of C<num> by default rather than
the usual simple scalar. (And in general, the type info is merely
@@ -404,7 +738,7 @@
is deliberately declared with a different dimensionality to provide a
different "view" on the actual value:
- my int @array[^2;^2] is Puddle .= new(:shape(^4) <== 0,1,2,3);
+ my int @array[2;2] is Puddle .= new(:shape(4) <== 0,1,2,3);
Again, reconciling those ideas is up to the implementation, C<Puddle>
in this case. The traits system is flexible enough to pass any
@@ -434,6 +768,7 @@
@x[0;1;42]
+
=head1 The semicolon operator
At the statement level, a semicolon terminates the current expression.
@@ -450,7 +785,7 @@
all the dimensions; if you don't, the unspecified dimensions are
"wildcarded". Supposing you have:
- my num @nums[^3;^3;^3];
+ my num @nums[3;3;3];
Then
@@ -466,7 +801,7 @@
But you should maybe write the last form anyway just for good
documentation, unless you don't actually know how many more dimensions
-there are. For that case you may use C<**>:
+there are. For that case use C<**>:
@nums[0,1,2;**]
@@ -524,7 +859,6 @@
0 .. Inf :by(2)
That's why we have C<..*> to mean C<..Inf>.
-
=head1 PDL signatures
To rewrite a Perl 5 PDL definition like this:
@@ -744,16 +1078,25 @@
=head1 Hashes
-Everything we've said for arrays applies to hashes as well, except that
-if you're going to limit the keys of one dimension of a hash, you have
-to provide an explicit list of keys to that dimension of the shape,
-or an equivalent range:
+Like arrays, you can specify hashes with multiple dimensions and fixed
+sets of keys:
+
+ my num %hash{<a b c d e f>}; # Only valid keys are 'a'..'f'
+ my num %hash{'a'..'f'}; # Same thing
+
+ my %rainfall{ Months; 1..31 } # Keys: Jan..Dec ; 1..31
- my num %hash{<a b c d e f>; Str};
- my num %hash{'a'..'f'; Str}; # same thing
+Unlike arrays, you can also specify a hash dimension via a non-
+enumerated type, which then allows all values of that type as keys in
+that dimension:
+
+ my num %hash{<a b c d e f>; Str}; # 2nd dimension key may be any string
+ my num %hash{'a'..'f'; Str}; # Same thing
+
+ my %rainfall{ Months; Int }; # Keys: Jan..Dec ; any integer
To declare a hash that can take any object as a key rather than
-just a string, say something like:
+just a string or integer, say something like:
my %hash{Any};
my %hash{*};
@@ -762,7 +1105,7 @@
my %hash{**};
-As with arrays, you can limit the keys to objects of particular types:
+You can limit the keys to objects of particular types:
my Fight %hash{Dog; Cat where {!.scared}};
@@ -785,8 +1128,6 @@
In list context, it returns a lazy list fed by the iterator. It must
be possible for a hash to be in more than one iterator at a time,
as long as the iterator state is stored in a lazy list.
-However, there is only one implicit iterator (the C<each> iterator)
-that works in scalar context to return the next pair. [Or maybe not.]
The downside to making a hash autosort via the iterator is that you'd
have to store all the keys in sorted order, and resort it when the
@@ -829,60 +1170,4 @@
This rule applies to C<Array>, C<Hash>, and C<Scalar> container objects.
-=head1 Negative subscript dwimmery
-
-It has become the custom to use negative subscripts to indicate counting
-from the end of an array. This is still supported, but only for unshaped
-arrays:
-
- my @a1 = 1,2,3;
- my @a2[*] = 1,2,3;
- @a1[-1] # 3
- @a1[-0.5] # also 3 (uses floor semantics)
- @a2[-1] # ERROR
- @a2[-0.0001] # ERROR
- @a2[0.0001] # 1
-
-For shaped arrays you must explicitly refer to the current endpoint
-using C<*>, the C<Whatever> object:
-
- @a2[*-1] # 3
- @a2[+*] = 1 # same as push(@a2, 1)
-
-When you use C<*> with C<+> and C<->, it creates a value of C<Whatever>
-but C<Num>, which the array subscript interpreter will interpret as the
-subscript one off the end of that dimension of the array. The lower
-right corner of a two dimensional array is C<@array[*-1; *-1]>.
-
-This policy has the fortuitous outcome that arrays declared with negative
-subscripts will never interpret negative subscripts as relative to the end:
-
- my @array[-5..5];
- @array[-1]; # always the 4th element, not the 11th.
- @array[*-1]; # always the 11th element, not the 4th.
-
-Oddly, this gives us a canonical way to get the last element, but no
-canonical way to get the first element, unless
-
- @array[*-*];
-
-works...
-
-Alternately, C<*+0> is the first element, and the subscript dwims
-from the front or back depending on the sign. That would be more
-symmetrical, but makes the idea of C<*> in a subscript a little more
-distant from the notion of "all the keys", which would be a loss,
-and potentially makes C<+*> not mean the number of keys.
-
-Conjecture: we might provide a way to declare a modular subscript that
-emulates the dwimmery, perhaps by using a subset type:
-
- subset Mod10 of Int where ^10;
- my @array[Mod5];
- @array[42] = 1; # sets @array[2]
- @array[582]; # returns 1
-
-But perhaps C<Mod10> should work just like C<^10>, and the modular behavior
-requires some extra syntax.
-
=for vim:set expandtab sw=4: