develooper Front page | perl.perl5.porters | Postings from April 2011

PATCH: pod/perllol.pod

Thread Next
From:
Tom Christiansen
Date:
April 26, 2011 17:44
Subject:
PATCH: pod/perllol.pod
Message ID:
85.1303865053@chthon
--- /home/tchrist/blead/pod/perllol.pod	2011-04-25 19:40:47.000000000 -0600
+++ ./perllol.pod	2011-04-26 18:31:07.000000000 -0600
@@ -6,23 +6,24 @@
 
 =head2 Declaration and Access of Arrays of Arrays
 
-The simplest thing to build is an array of arrays (sometimes imprecisely
-called a list of lists).  It's reasonably easy to understand, and
-almost everything that applies here will also be applicable later
-on with the fancier data structures.
+The simplest two-level data structure to build in Perl is an array of
+arrays, sometimes casually but imprecisely called a list of lists.  
+It's reasonably easy to understand, and almost everything that applies 
+here will also be applicable later on with the fancier data structures.
 
 An array of an array is just a regular old array @AoA that you can
 get at with two subscripts, like C<$AoA[3][2]>.  Here's a declaration
 of the array:
 
+    use 5.010;  # so we can use say()
+
     # assign to our array, an array of array references
     @AoA = (
-	   [ "fred", "barney" ],
-	   [ "george", "jane", "elroy" ],
-	   [ "homer", "marge", "bart" ],
+	   [ "fred", "barney", "pebbles", "bambam", "dino", ],
+	   [ "george", "jane", "elroy", "judy", ],
+	   [ "homer", "bart", "marge", "maggie", ],
     );
-
-    print $AoA[2][2];
+    say $AoA[2][1];
   bart
 
 Now you should be very careful that the outer bracket type
@@ -33,11 +34,11 @@
     # assign a reference to array of array references
     $ref_to_AoA = [
 	[ "fred", "barney", "pebbles", "bambam", "dino", ],
-	[ "homer", "bart", "marge", "maggie", ],
 	[ "george", "jane", "elroy", "judy", ],
+	[ "homer", "bart", "marge", "maggie", ],
     ];
-
-    print $ref_to_AoA->[2][2];
+    say $ref_to_AoA->[2][1];
+  bart
 
 Notice that the outer bracket type has changed, and so our access syntax
 has also changed.  That's because unlike C, in perl you can't freely
@@ -88,16 +89,18 @@
 	$AoA[$i] = [ @tmp ];
     }
 
-It's very important that you make sure to use the C<[]> array reference
-constructor.  That's because this will be very wrong:
-
-    $AoA[$i] = @tmp;
+It's important you make sure to use the C<[ ]> array reference
+constructor around the array.  That's because this wouldn't work:
 
-You see, assigning a named array like that to a scalar just counts the
-number of elements in @tmp, which probably isn't what you want.
+    $AoA[$i] = @tmp;   # WRONG!
 
-If you are running under C<use strict>, you'll have to add some
-declarations to make it happy:
+The reason that doesn't do what you may think is because assigning a
+named array like that to a scalar is taking an array in scalar
+context, which means it just counts the number of elements in @tmp.
+
+If you are running under C<use strict>--and if you aren't, why in
+the world I<aren't> you?--you'll have to add some declarations to
+make it happy:
 
     use strict;
     my(@AoA, @tmp);
@@ -118,14 +121,14 @@
     my (@AoA, $i, $line);
     for $i ( 0 .. 10 ) {
 	$line = <>;
-	$AoA[$i] = [ split ' ', $line ];
+	$AoA[$i] = [ split " ", $line ];
     }
 
 or even just
 
     my (@AoA, $i);
     for $i ( 0 .. 10 ) {
-	$AoA[$i] = [ split ' ', <> ];
+	$AoA[$i] = [ split " ", <> ];
     }
 
 You should in general be leery of using functions that could
@@ -134,7 +137,7 @@
 
     my (@AoA, $i);
     for $i ( 0 .. 10 ) {
-	$AoA[$i] = [ split ' ', scalar(<>) ];
+	$AoA[$i] = [ split " ", scalar(<>) ];
     }
 
 If you wanted to have a $ref_to_AoA variable as a reference to an array,
@@ -165,14 +168,45 @@
 to do something a bit funnier looking:
 
     # add new columns to an existing row
-    push @{ $AoA[0] }, "wilma", "betty";
+    push @{ $AoA[0] }, "wilma", "betty";   # explicit deref
+
+Prior to Perl 5.14, this line wouldn't even compile with the C<@{...}>:
+
+    push $AoA[0], "wilma", "betty";        # implicit deref
+
+How come?  Because once upon a time, the argument to push() had to be be a
+real array, not just a reference to one. That's no longer true.  In fact,
+the line marked "implicit deref" above works just fine--in this
+instance--to do what the one that says explicit deref did.
+
+The reason I said "in this instance" is because that I<only> works
+because C<$AoA[0]> already held an array reference.  If you try that on an
+undefined variable, you'll take an exception.  That's because the implicit
+derefererence will never autovivify an undefined variable the way C<@{...}> 
+always will:
+
+    my $aref = undef;
+    push $aref,  qw(some more values);  # WRONG!
+    push @$aref, qw(a few others);      # ok
 
-Notice that I I<couldn't> say just:
+If you want to take advantage of this new implicit dereferencing behavior,
+go right ahead: it makes code easier on the eye and wrist.  Just understand
+that older releases will choke on it during compilation.  Whenever you make
+use of something that works only in some given release of Perl and later,
+but not any earlier, you should place a prominent
 
-    push $AoA[0], "wilma", "betty";  # WRONG!
+    use v5.14;   # needed for implicit deref of array refs by array ops
 
-In fact, that wouldn't even compile.  How come?  Because the argument
-to push() must be a real array, not just a reference to such.
+directive at the top of the file that needs it.  That way when somebody
+tries to run the new code under an old perl, rather than getting an error like
+
+    Type of arg 1 to push must be array (not array element) at AoA line 8, near ""betty";"
+    Execution of AoA aborted due to compilation errors.
+
+they'll be politely informed that
+
+    Perl v5.14.0 required--this is only v5.12.3, stopped at AoA line 1.
+    BEGIN failed--compilation aborted at AoA line 1.
 
 =head2 Access and Printing
 
@@ -194,20 +228,20 @@
 set of subscripts.
 
     for $aref ( @AoA ) {
-	print "\t [ @$aref ],\n";
+	say "\t [ @$aref ],";
     }
 
 If you wanted to keep track of subscripts, you might do this:
 
     for $i ( 0 .. $#AoA ) {
-	print "\t elt $i is [ @{$AoA[$i]} ],\n";
+	say "\t elt $i is [ @{$AoA[$i]} ],";
     }
 
 or maybe even this.  Notice the inner loop.
 
     for $i ( 0 .. $#AoA ) {
 	for $j ( 0 .. $#{$AoA[$i]} ) {
-	    print "elt $i $j is $AoA[$i][$j]\n";
+	    say "elt $i $j is $AoA[$i][$j]";
 	}
     }
 
@@ -217,7 +251,7 @@
     for $i ( 0 .. $#AoA ) {
 	$aref = $AoA[$i];
 	for $j ( 0 .. $#{$aref} ) {
-	    print "elt $i $j is $AoA[$i][$j]\n";
+	    say "elt $i $j is $AoA[$i][$j]";
 	}
     }
 
@@ -227,18 +261,65 @@
 	$aref = $AoA[$i];
 	$n = @$aref - 1;
 	for $j ( 0 .. $n ) {
-	    print "elt $i $j is $AoA[$i][$j]\n";
+	    say "elt $i $j is $AoA[$i][$j]";
 	}
     }
 
+When you get tired of writing a custom print for your data structures,
+you might look at the standard C<Dumpvalue> or C<Data::Dumper> modules.
+The former is what the Perl debugger uses and so is easier to read, 
+while the latter generates valid Perl code so is easier to parse.  
+
+For example:
+
+    use v5.14;     # using the + prototype, new to v5.14
+
+    sub show(+) {
+	require Dumpvalue;
+	state $prettily = new Dumpvalue::
+			    tick        => q("),
+			    compactDump => 1,  # comment these two lines out
+			    veryCompact => 1,  # if you want a bigger dump
+			;
+	dumpValue $prettily @_;
+    }
+
+    # Assign a list of array references to an array.
+    my @AoA = (
+	   [ "fred", "barney" ],
+	   [ "george", "jane", "elroy" ],
+	   [ "homer", "marge", "bart" ],
+    );
+    push $AoA[0], "wilma", "betty";
+    show @AoA;
+
+will print out:
+
+    0  0..3  "fred" "barney" "wilma" "betty"
+    1  0..2  "george" "jane" "elroy"
+    2  0..2  "homer" "marge" "bart"
+
+Whereas if you comment out the two lines I said you might wish to,
+then it shows it to you this way instead:
+
+    0  ARRAY(0x8031d0)
+       0  "fred"
+       1  "barney"
+       2  "wilma"
+       3  "betty"
+    1  ARRAY(0x803d40)
+       0  "george"
+       1  "jane"
+       2  "elroy"
+    2  ARRAY(0x803e10)
+       0  "homer"
+       1  "marge"
+       2  "bart"
+
 =head2 Slices
 
 If you want to get at a slice (part of a row) in a multidimensional
 array, you're going to have to do some fancy subscripting.  That's
 because while we have a nice synonym for single elements via the
 pointer arrow for dereferencing, no such convenience exists for slices.
-(Remember, of course, that you can always write a loop to do a slice
-operation.)
 
 Here's how to do one operation using a loop.  We'll assume an @AoA
 variable as before.
@@ -251,9 +332,13 @@
 
 That same loop could be replaced with a slice operation:
 
+    @part = @{$AoA[4]}[7..12];
+
+or spaced out a bit:
+
     @part = @{ $AoA[4] } [ 7..12 ];
 
-but as you might well imagine, this is pretty rough on the reader.
+But as you might well imagine, this can get pretty rough on the reader.
 
 Ah, but what if you wanted a I<two-dimensional slice>, such as having
 $x run from 4..8 and $y run from 7 to 12?  Hmm... here's the simple way:
@@ -300,4 +385,4 @@
 
 Tom Christiansen <F<tchrist@perl.com>>
 
-Last update: Thu Jun  4 16:16:23 MDT 1998
+Last update: Tue Apr 26 18:30:55 MDT 2011

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About