· 7 years ago · Sep 28, 2018, 02:14 AM
1# Perl References
2
3Simple Perl variables are called `scalars`. Examples of scalar values are
4
5```perl
6 $number = 123;
7 $string = "String";
8 $file_handle = open "<filename";
9 $null_value = undef;
10 $reference = \"Reference of a String";
11```
12
13Perl has a few simple data types. Each is determined from the variable prefix symbol when declared, or when you want a non-scalar set of variables returned.
14
15* $variable - A scalar type
16* @variable - An array type
17* %variable - A hash type
18* & - A code type, though this is never a type of a variable
19
20Complex variables can hold multiple scalar variables. These are Arrays, Hashes, Globs, and Objects.
21
22When references or defining the whole structure, we use the type prefix as above, but when access a scalar value within one, we use the $ prefix to denote
23
24### Array
25
26The array holds a list of scalar values.
27
28```perl
29 @array = (1, 2, 'three', $file_handle, undef);
30 $array[1] #=> 2 ## Second element array (start counting at 0)
31 @array[1,2] #=> (2, 'three') ## A "slice" as list of elements selected from array
32
33 $#array #=> 4 ## Last element index of array. Avoid this odd syntax.
34 scalar(@array) #=> 5 ## Number of elements in the array
35
36 push @array, 123; ## Appends value(s) to the end of the array
37 pop @array; #=> 123 ## Removes and returns the last element of the array
38 unshift @array, 123; ## Prepends value(s) onto the head of the array
39 shift @array #=> 123 ## Removes and returns the first element from the array
40
41 foreach $element (@array) { # The foreach structure iterates over the loop
42 print $element
43 }
44
45 for ($i=0; $i<scalar(@array); $i++) {
46 print $array[$i];
47 }
48
49```
50
51### Hash
52
53A Hash is also known as a dictionary or associative array. It provides a key/value structure to set and retrieve values by a key value. It is a special case of a list, and decomposes back into a list when assigned or sent as a function parameter.
54
55```perl
56 %hash = (one=>1, two=>2, three=>3);
57
58 $hash{one}; #=> 1 ## The associated value for the key value of "one"
59 @hash{'one', 'two'}; #=> (1, 2) ## Returns a sliced list of values
60
61 %hash #=> ('one', 1, 'two', 2, 'three', 3) ## Decomposes into a list
62 keys %hash #=> ('one', 'two', 'three') ## List of keys
63 values %hash #=> (1, 2, 3) ## List of values
64 exists $hash{$key} #=> Boolean ## Hash operator returns true if key exists in the hash
65 delete $hash{three}; #=> 3 # Deletes key/value from hash, returns the value
66
67 while ( ($key, $value) = each %hash) { # Iterates over a hash
68 print $key, $value;
69 }
70
71 foreach $key (keys %hash) { # Iterates over a hash by key value
72 print $key, $hash{$key};
73 }
74```
75
76Note: When iterating over a hash using `each`, it keeps a "cursor" in the hash of the current key/value pair. If you do not finish iterating, the next time you start iterating, it will continue where it left off instead of at the first key/value pair of the hash. To reset the cursor, call `keys %hash` before iteration.
77
78## References
79A `reference` value does not hold one of these complex data types, but a "pointer" to one. A reference to a scalar can be used with the \\ referencing operator, the [ ] array reference construct, or a { } hash construct.
80
81The reference is dereferenced with the double-dollar ($$refname) variable, or with the -> arrow for array and hash element references.
82
83```perl
84 $i = 123; ## A scalar
85 $iref = \$i; #=> SCALAR(0x80108d678) ## Reference to scalar
86 $$iref; #=> 123; ## Dereferencing the scalar reference
87
88 @arr = (1,2,3)
89 $aref = \@arr; #=> ARRAY(0x80108d678)
90 @$ref; #=> (1, 2, 3)
91 $aref = [1,2,3] #=> ARRAY(0x80108d678)
92 @$ref; #=> (1, 2, 3)
93 $ref->[1]; #=> 2 ## Second element of array
94
95 scalar(@$aref) #=> 3 ## Number of elements in the referenced array
96 $#{$a} #=> 2 ## Last element index in the references array (like @#arr)
97 $#{[]} #=> -1 ## ... Empty arrays return -1.
98
99 %hash = (one=>1, two=>2, three=>3);
100 $href = \%hash; #=> ARRAY(0x80108d6f0) ## Hashes are also arrays
101 %hash = %$hash; #=> ('one', 1, 'two', 2, 'three', 3)
102 $href = {one=>1, two=>2, three=>3};
103 #=> ARRAY(0x80108d6f0) ## Hashes are also arrays
104 $href->{one} #=> 1
105```
106
107## Usage: Passing data to functions
108
109When you call a Perl function, it generates an array of the arguments and invokes the function. The function uses the special default array variable, @_ and uses the positions of the arguments as the parameters.
110
111```perl
112 myfunction($i, $s); #=> sets @_ = (123, "String");
113```
114
115The called function parses the incoming argument list with standard Perl notation:
116
117```perl
118 ($first, $second, @rest) = @_;
119```
120
121That statement takes the incoming argument array, and puts the first element in $first, the second in $second, and the remaining arguments (if any) to into the @rest array.
122
123When you pass an array or hash (which is really just an array anyway) to a function, it "flattens" out the array and passes each value of the array as a positional parameter.
124
125```perl
126 myfunction($i, @arr, %hash); => sets @_ = (123, 1, 2, 3, 'name', 1, 1, "one", "etc.", $i);
127```
128
129Oops! Now myfunction() doesn't know where the array begin and ends, nor where the hash begins or ends. The only thing it knows for sure is the first argument since that in a simple scalar.
130
131This can be desired, as long as each parameter is a simple value, and the last parameter is an array or hash.
132
133```perl
134 myfunction($i, @arr); #=> Sets @_ to (123, 1, 2, 3);
135 #...
136 sub myfunction {
137 my ($i, @arr) = @_; #=> allows function to reconstruct the parameters
138 }
139```
140
141But what if you need to pass both an array AND a hash to a function? This is where references save the day. Since a reference to an array or hash is a single value, the reference to the whole array takes only one positional argument.
142
143
144```perl
145 myfunction($i, \@arr, \%hash);
146 #...
147 sub myfunction {
148 my ($i, $aref, $href) = @_; #=> $i is 123, $aref and $href are references.
149 @$aref; #=> (1, 2, 3)
150 %$hash; #=> (name=>1, 1=>"one", "etc."=>$i)
151 }
152```
153
154Function can also use this technique to return an array of values to a caller.
155
156```perl
157 return ($i, \@arr, \%hash);
158```
159
160There is also an added performance benefit of passing references instead of whole arrays and hashes. For large structures, it takes time copying each element from the array into the @_ variable. Instead, only a single reference variable is needed to be passed into the @_ argument list. In computer science, this is known as "passing by reference" instead of "passing by value".
161
162Lastly, when you pass a reference into a function, that function can change the value of the passed variable "in place" without getting returned explicitly. This technique is useful at time, but sometimes these "side effect" practices are discouraged, so use this only when it makes sense, okay?
163
164```perl
165 sub myfunction {
166 $iref = shift; # Shifts first value off of @_ array
167 ++$$iref; # Increment the value at the reference
168 }
169 #...
170 $j = 123; #=> 123
171 myfunction(\$j); # myfunction() will change the value of $j
172 $j; #=> 124
173```
174
175While this example demonstrated the concept, this is one of those cases where it is not okay to do this. I would instead not use the reference and have the code return the new value.
176
177## Usage: Data Structures
178
179A `table` or 2-dimensional array is not a native perl datatype as it is in many languages. Instead, perl allows you to build your own as an array of arrays. Now since perl array elements can only be scalar variables, we need to use a reference instead. So a perl table is actually an array of references.
180
181```perl
182 @row1 = (1, 2, 3);
183 @row2 = (4, 5, 6);
184 @table = (\@row1, \@row2);
185
186 $table[0]->[1]; # => 2 ## Value of first row, second column
187 $table[0][1]; # => 2 ## Any second-level subscript/hash on array implies the ->
188```
189
190Often, it's best to bite the bullet and fully embrace a reference when you are using a data structure like this. It helps me to think of it as a starting point, and makes the syntax more friendly in the long run.
191
192```perl
193 $table = [ [1,2,3], [4,5,6] ]; # Table is a reference of arrays of arrays :-)
194 $table->[0][1]; #=> 2
195 $table[0][1]; # Wrong! # Error! Expecting $table[0]->[1] but $table is a reference, not array
196```
197
198See how I defined the table using the [ ] array reference syntax? It should make it more clear to write and read. Also, the table subscripts are now together, not separated by the -> dereferencing pointer.
199
200Also, see the difference of addressing table elements set up as starting with an array instead of a array reference? It can trip you up, and I suggest always use a reference to avoid the confusion, because mixing syntax styles in a program is painful. Using a consistent syntax within a large program and complex data structures reduces chances for errors.
201
202```perl
203 @table = ([1,2,3], [4,5,6]); # Avoid: array of references
204 $table[0][1]; #=> 2 ## While this works nicely...
205 $table[0]->[1]; #=> 2 ## ... this is what perl does
206
207 $table = [ [1,2,3], [4,5,6] ]; # Suggested: start off with a reference
208 $table->[0][1]; #=> 2 ## Only way to access the element
209
210 $reference->{key} # This makes a consistent usage for all data structures
211 $reference->{key}[0]; # ... Hash of arrays
212 $reference->[0]{key}; # ... Array of hashes
213```
214
215A result set of database rows are best represented as an array of hash references, where each row is a (colname=>value) hash. Again, let's start with a reference to the result set.
216
217```perl
218 $rows = []; # Initialize $rows as array reference
219 push @$rows, {id=>1, name=>"Allen"}; # Add first row, a hash reference.
220 push @$rows, {id=>2, name=>"Bob"}; # Second row
221
222 # Get at the data by $rows->[row_number]{column_name_as_hash_key}
223 $rows->[0]{name}; #=> Allen
224```
225
226Did you follow all that? You may want to parse through it a few times. Here are a few notes:
227
228* @$rows - Push expects an array, we use the @ to dereference the as an array so push can do its thing.
229* {column_name=>row_column_value} - We use the {} hash reference syntax to create the data row.
230* $rows - This returns an array reference for the result set
231* $rows->[0] - returns the first row on the rows array, which is a hash reference
232* $rows->[0]{name} - returns the corresponding value for the key "name" in the first row.
233
234## Dereferencing References of References
235
236Now for the fun part. We saw how to dereference a reference with the `<typeoperator>$referencevariable` syntax and -> operator to navigate through a series of nested references.
237
238```perl
239 @arr = @$array_reference;
240 %hash = %$hash_reference;
241 $i = $$scalar_reference;
242
243 $array_reference->[0];
244 $hash_reference->{key};
245 $array_of_hashes->[0]{key};
246 $array_of_arrays->[0][2]; ## a 2-Dimensional table
247 $three_dim_table->[0][1][2];
248 $arr_hash_array=>[1]{key}[2];
249```
250
251Now say we want to operate on a array reference returned from the -> operator. To dereferences an expression like this we use the `@{expression}` syntax for an array reference and the `%{expression}` syntax for a hash reference.
252
253Here is now this works with our 2-dimensional table structure
254```perl
255 $table = [ [1,2,3], [4,5,6] ];
256 $table->[0]; # Returns a reference to [1,2,3]
257 @row = @{$table->[0]}; # Returns the array of (1, 2, 3)
258 push @{$table->[0]}, 0; # $table is now [ [1,2,3,0], [4,5,6] ]
259
260 scalar(@{$table->[1]}) #=> 3 ## The number of items of the second row
261 $#{$table->[1]} #=> 2 ## Index of last element in the referenced array (-1 when empty)
262 @{$table->[1]}[1, 2] #=> (5, 6) ## Slice of array, returns table[1][1,2] as a list
263
264 foreach $row_ref (@$table) { # Iterate over each row
265 foreach $value (@$row_ref) { # Iterate over each column in that row
266 $value; # Do something with each value in the table
267 }
268 }
269
270 for ($i=$#{$table}; $i>=0; $i--) { # Reverse iteration by index
271 for ($j=$#{$table->[$i]}; $j>=0; $j--) { # ... reverse iteration for each row
272 $table->[$i][$j] += $prev; # Do something with that referenced location
273 $prev = $table->[$i][$j]; # ... Totally contrived example
274 }
275 }
276```
277
278Now let's look at our result set "Array references of hash references"
279```perl
280 $rows = [ {id=>1, name=>"Allen"}, {id=>2, name=>"Bob"} ]; # Array Ref of Hashes
281 $rows->[0]; # Returns reference to the first row
282 %hash = %{$rows->[0]}; # Deferences the first row as a hash
283 @hash_keys = keys %{$rows->[0]}; # ... and now return its keys
284
285 foreach $hash_key (keys @{$rows->[0]}) { } # Iterate over the keys
286 while (($k,$v) = each %{$rows->[0]) { } # Iterate over the "row"
287
288 foreach $row_ref (@$rows) { # Iterate over each row
289 while (($k,$v) = each %{$rows->[0]) { # Iterate over each key-value pair
290 ($k, $v); # Do something with each pair
291 }
292 }
293```
294
295## Inspecting the reference for type
296
297Okay, now imagine you need to write a subroutine that takes a reference, and need to determine what the datatype is for the reference?
298
299The `ref` unary operator takes a variable and returns the datatype. It is the "type of" operator, but does not distinguish between scalar types (string, number, undef, file handles).
300
301```perl
302 ref 'asdf' #=> '' ## Non-reference values return the empty string
303 ref [1,2,3] #=> 'ARRAY'
304 ref {a=>12} #=> 'HASH'
305 ref sub {} #=> 'CODE' ## Code object (see below)
306 ref \123 #=> 'SCALAR' ## Reference to a scalar
307 ref new MyClass #=> 'MyClass' ## Objects return their package/class name
308
309 ref undef #=> '' ## Even undefined values (null/nil) are scalar
310 defined(undef); #=> False ## A False condition, but no value returned
311
312 $r = [{a=>1}];
313 ref $r #=> 'ARRAY' ## Array of Hashes
314 ref $r->[0] #=> 'HASH' ## Deference to the Hash
315```
316
317Congratulations, you are now a master of basic perl references!
318
319## References to Code
320
321But wait! There's more! You can also have references to "code" functions and closures. Older versions of perl used the `&myfunction()` syntax to call a function, but the & operator has been dropped as it was not necessary. However, it is still needed to deferences a code reference.
322
323```perl
324 sub myfunc { 123; } # A simple function
325
326 $code_ref = \&myfunc; # Take a reference to your subroutine
327
328 # These do not work! &myfunc() will alway run the function, not reference it
329 &myfunc(); #=> 123 ## The parens executes the code
330 \&myfunc(); #=> SCALAR(0x100804ed0) ## Executes Returns ref to 123
331
332 @array = my_map(\@array, \&myfunc); # Pass code reference to another function.
333
334 # Execute the code reference. We can also pass in any arguments it needs.
335 &$code_ref(); #=> 123
336```
337
338### Closures
339
340Closures are a cool trick, stolen outright from the Lisp universe. It is a block of code that is passed to another function or stored for later execution, much like we saw before.
341
342The really cool part is this code block executes in the *context* of when it was defined. It has access to all the variables in the scope when it was created, and can alter them, even when invoked from within another function.
343
344One of the useful things we can do with closures is to create a callback code block that injects our specific logic into a general purpose routine.
345
346Closures are "anonymous code blocks" using the `sub { }` syntax (like a subroutine definition without a name).
347
348```perl
349 $i = 1;
350 $closure = sub { ++$i; } # Reference to a closure
351 &$closure(); # Run the reference
352 $i; #=> 2
353```
354
355Let's build a useful function to tie this all together. Perl has a `map` construct that iterates over an array, injects a value into a block, and returns an array of values returned from the block. It does *not* use a closure, but it a language syntax construct. For instance:
356
357```perl
358 @array = ( 1, 2, 3);
359 @array = map { $_ + 1 } @array; # Adds 1 to each element in the array
360 @array #=> (2, 3, 4)
361
362 # Alternate (non-map) way to do this:
363 @result = ();
364 foreach (@array) { push @result, $_ + 1; }
365 @array = @result;
366```
367
368It's a simple, but rather ugly syntax. It sets the $_ variable inside the block for each value of the array.
369
370Suppose we want to create an map-like iterator for a hash. We can write a general routine, map_hash(), that iterates over a hash, and executes a passed closure (or code block) for each key-value pair. The routine passed back a key-value pair, either the same or changed. map_hash() returns a new hash of the result pairs.
371
372```perl
373 sub map_hash {
374 ($hash_ref, $block_ref) = @_; # Args: map_hash(\%hash, sub {} );
375 keys %$hash_ref; # Resets hash iterator in case it was not finished
376 %result = ();
377 while ( ($k,$v) = each %$hash_ref) {
378 ($k, $v) = &$block_ref($k, $v); # Calls the closure or code block
379 %result{$k} = $v; # Place new key-value in result hash
380 }
381 %result; # Returns the new hash
382 }
383
384 # Call map_hash to upper-case the keys of a hash.
385 %hash = (a=>1, b=>2);
386 %hash = map_hash(\%hash, \&uc_hash_keys);
387 %hash; #=> (A=>1, B=>2)
388
389 sub uc_hash_keys {
390 ($k, $v) = @_; # Input arguments: key, value pair
391 (uc $k, $v); # Return upper-cased key, value pair
392 }
393
394 # Call map_hash to sum the values of all keys in the hash
395 $total = 0; # The closure has access to all local vars!
396 %hash = map_hash(\%hash,
397 sub { # Create a closure to
398 ($k, $v) = @_; # Input arguments: key, value pair
399 $total += $v; # Adds value to total defined above
400 ($k, $v); # Return unchanged key, value pair
401 }
402 );
403 $total; #=> 3
404```
405
406# Classes and Object Oriented Perl
407
408Wait! What is this doing here? We are talking about Perl References, right? Well, the perl object model really is just a reference "blessed" with a package name. You can execute any method (a function in OOP is now called a method) in that package using the -> operator.
409
410```perl
411package Person; # Define our Person class
412
413sub talk {
414 ($self, $message) = @_; # Self is the object reference always passed in
415 print "$self->{name} says $message \n";
416}
417
418package main; # Change back to our "main" namespace
419
420$person = {id=>1, name=>"Allen"}; # $person is a hash reference
421bless $person, Person; #=> Person=HASH(0x100804ed0)
422# Now $person is a instance of class Person (implemented with a hash).
423
424# Call a method on the person object reference
425$person->talk("hi"); #=> Allen says hi
426```
427
428Of course, there is more to understand about object-oriented perl than this basic example. I wanted to demonstrate that perl objects are also references, and require the same syntax.
429
430Also, you see that all perl objects are specially "blessed" references of perl hashes, arrays, or other things you can reference. Though, you will find that 99.99% of the time, it will be a hash, because the hash keys become the instance variables of the object.