5 PERL VARIABLES

Perl stores information in a variety of data constructs loosely called variables. Although our computer only understands the most basic forms of data, such as chars, ints, and floats, Perls data constructs permit the storage and retrieval of information without having to concern ourselves with the specifics of data typing our variables, or allocating the necessary space in ram for their correct storage.

We have already become familiar with Perls most basic memory storage device, the scalar variable. Scalar variables can store all the common basic data types, such as floats, but also can store strings and treat them as singular pieces of data. All Scalar variables have the notation of $ in front of the symbol used to reference the variable. An example of this is $myscalar.

When you create the variable $myscalar in Perl, you are actually creating a table called *myscalar. This is referred to as a typeglob in Perl talk. This symbol has a link to it the scalar version of this variable. This permits us to use the same name for a scalar as we do for other data constructions in perl. In addition to there being a table of data constructions for each symbol Perl stores all of its typeglobs in a table called a package. We will come back to this repeatedly as our programming techniques become more advanced.



Arrays and Lists

In addition to Perls basic data construct, the scalar, Perl also supports a List of scalars in a separate constructions. We have seen some lists in the previous section without formal introduction. In the general form a list looks like this:

@mylist = ($scalar1, $scalar2, ....);

Here, the list is built with the parenthesis, each scalar value separated by the comma. While I defined this list with scalars variables, it is the scalar values that make the components of the list. The following are all valid lists:

@mylist = (3,2,1,"Three", "Two", "One");
@mylist = qw(The Meek Shall Inherit The Earth);
@mylist = split /\s/ $somestring;
@mylist = (3 => THREE, 2=>Two, 1=>One);

In the last case, recall that '=>' and ',' both represent the comma.

Lists can be stored in Perl Arrays. Perl arrays create symbols that are type globs, just as scalars do, and are recognized by the @ character before the symbol name. The type glob *myvalue can reference the scalar, $myvalue, and the array @myvalue.

Normally we would think we could assign a list with an array to another array, and so we can.

@mynewarray = @myfirstarray;

We can even assign a list contained into an array, directly to a list of scalars in an explicit list:

($ONE, $TWO) = @myfirstarray;

In this case only the first to scalar values in @myfirstarray are assigned. Any values after the first two scalars values are ignored.

In the case where less scalar values are being assigned than scalar values in a list, then the remaining values remain undefined or unchanged. This is basically intuitive. Perl often behaves as you would think it should. When functions returns lists, this may not be the case. You need to look at the documentation of your function call.

If we want to assign an element of a list to a scalar, we can access individual values with an index. The first scalar value is assigned index 0 as follows:

$result = $myfirstarray[0];

Notice that when we desire to access a single array element, we use the scalar $ character in front of the symbol. The @ character is only used when we are processed the array in a list context. Thus, we could say:

$result = $myfirstarray[1];

and

@mysecondarray = @myfirstarray;

If we try to assign the list contained in an array to a single scalar variable, Perl does an act of kindness for us and returns the size of the array (one greater than the highest defined index value).

$count = @myfirstarray; #This returns the size of the array.

This is actually used to our advantage and is a useful idiom:

for($i = 0; $i<@myfirstarray; $i++){
	print $myfirstarray[$i];
}
This commonly used C programming syntax is commonly seen in Perl programs, although we can do the same thing without this complexity as follow:
for $value (@myfirstarray){
	print $value;
}
We can get the last index number with $#myarray notation. This is not the same as the scalar return of @myarray. By default $#myarray is one less than @myarray because $#myarray is the actual highest index where as @myscalar returns the size of the array as an integer. $#myarray can also be assigned to enlarge to size of the array if it is used as a left value.

@myarray = qw(ONE TWO THREE);
$index = $#myarray; # index is 2
$#myarray = 10; #Array expanded to 11 elements 0-10
$#myarray = 0; Clears the array

If we assign @myarray, we destroy the data within it and the integer is assigned to the first element (index 0); So far we have seen $myarray[0], and @myarray. Perl also provides for the last possibility @myarray[0]. More exactly, @myarray[0] represents an array slice. We can quickly target a subset of our list for assignment to another array as follows:

@mysecondarray = @myfirstarray[1,3];

Perl makes special cases of list slices of numbers and letters. Thus @myarray = (0..10) will assign the entire list (1,2,3,4,5,6,7,8,9,10) to @myarray. @myarray = (a-z); will assign the alphabet.

Try the following program and see if you can identify what each line is doing in the manipulation of arrays.


 
 file30.pl.html
 
 
 
 #!/usr/bin/perl  
 
 @myfirstarray = ("One", "Two", "Three");
 ($one, $two) = @myfirstarray;
 
 print "$one $two\n";
 
 ($one, $two, $three, $four) = @myfirstarray;
 print "$one $two $three, $four\n";
 
 for $value (@myfirstarray){
         print "$value\n";
 }
 
 @mysecondarray = @myfirstarray[1,2];
 
 print "The Second Array " . "@mysecondarray" ."\n";
 $mystring = "The meek shall inherit the earth\n";
 ($firstword, $secondword) = split /\s+/, $mystring;
 print "$firstword, $secondword\n";
 
 @words = split /\s+/, $mystring;
 ($firstword, $secondword) = @words;
 print "$firstword, $secondword\n";
 
 $count = @words;
 print "$count\n";
 
 $count = $#words;
 print "$count\n";
 
 $#words = 10;
 $count = $#words;
 print "$count\n";
 
 ($firstword, $secondword, @leftover) = @words;
 print "$firstword, $secondword, @leftover \n";
 
 (@leftover, $firstword, $secondword) = @words;
 print "$firstword, $secondword, @leftover \n";
 
 #qw!$firstword $secondword @leftover! = @words; Can Not Work with an internal array
 
 @words = qw!The Meek Shall Inherit The Earth!;
 ($firstword, $secondword, $thirdword) = @words[2..4];
 print "$firstword,$secondword, $thirdword\n";
 
 $#words = 15;
 
 $index = $#words;
 print "\$index ==>$index\n";
 
 @words = 20;
 $index = $#words;
 print "\$index ==>$index\n";
 print "\$index ==>$index :$words[0] is index 0: $words[1] :is in index 1\n";
 
 @words = (1..10);
 print "@words";
 print "\n";
 
 @words = (a..z);
 print "@words";
 print "\n";
 
 @words = (apple..zoo);
 print "@words";
 print "\n";
 
 @words = (A..z);
 print "@words";
 print "\n";
 
 @words = (a - z);
 print "@words";
 print "\n";
 
 @words = (5 - 2);
 print "@words";
 print "\n";
 



List Function and Operators

Perl has an arsenal of functions which perform magic on arrays. Two which we have seen already is join and split. Join takes a delimiter as an argument and a list, and returns a string. split takes a string and creates a list tokenizing the string on a pattern. In addition to join, other functions which work of lists or arrays include:

push
pop
shift
splice
unshift
grep
map
reverse
sort
unpack

Some of these functions can only work on list variables (arrays). Others work with list data, and don't strictly need arrays. push, pop, shift and unshift manipulate the content of arrays and allow us to create easy stacks or streams. These can be very useful for making data constructions.

push takes 2 arguments, an array which we are building, and a list, and returns the size of your array. $array_size = push @array (LIST);

push(@dictionary, qw(Honor your father and mother);

pop takes one argument, an array. It removes from the array the last element and returns it to a scalar. Together they can manipulate a stack. This sort of data construction is useful for some parsing routines and logic operators. Parsers and compilers make extensive use of stacks to correctly interpret programming code.

I simple stack might look like this:
push @function, qw(three plus two);

$argument1 = pop @function;
$operator1 = pop @function;
$argument2 = pop @function;

print "$argument1, $operator1, $argument2\n";
;
We can then translate all the arguments and push back onto the stack the result using curly braces and next. I leave that for the student to write.

push and pop function like on a stack. They treat data like pancakes. The first element in the list is placed on the bottom, and the next on top and so on. pop retrieves them in the same fashion. It removes the top one first and works it way down to the bottom.


 
 file31.pl.html
 
 
 
 #!/usr/bin/perl
 
 @words = qw(The meek shall inherit the Earth);
 @words = sort(@words);
 while ($count = @words){
         $ret = push @dictionary, pop @words;
         print "\$count $count \$ret $ret\n";
 }
 print "\@dictionary @dictionary \@words @words\n";
 
 $ret = push @words, @dictionary;
 print "\$ret $ret \n\@dictionary @dictionary \n\@words @words\n";
 $ret = push @words, @dictionary;
 print "\$ret $ret \n\@dictionary @dictionary \n\@words @words\n";
 
 push @dictionary, qw(Honor your father and mother);
 print "@dictionary\n";
 
 

The sisters of push and pop is shift and unshift. If we build an array as follows:

@numbers = qw( one two three);

then the value of scalar(@numbers) is 3, @#numbers has the value of 2, and $numbers[0] is the string "one". shift takes an array as an argument. It returns the first element of the array ($numbers[0]) and removes it from the array, moving all the elements down on index.

In our example:

$tmp = shift @numbers;

$tmp is now holds the value of "one", $numbers[0] holds the value of "two", scalar(@numbers) returns 2, and @#numbers is equal to 1. In esense, the first element rolls off the list stored in the array and all the rest of the elements move up one. Using push and shift together can create effective stream buffers of information.

unshift is to shift what push is to pop. Push puts a list on the end of an array. unshift puts a list at the beginning of an array, and moving all the rest of the elements up in the index.

unshift @numbers, qw(one two);

The elements in this array will be "one", "two", and the rest of the array follows in there original order. More generalized is the function splice. Splice can remove and replace list elements of the array at will, similar to splicing a film. The syntax of splice an be a bit trying:

splice array, offset, list

Let's first create a sizable array:

@numbers = qw(zero one two three four five six seven eight nine ten); @capture = splice( @number, 1, 3, qw(alpha beta charlie)); @number now has the elements one, two, three replaced by alpha, beta, and charlie. But alpha, beta, charlie doesn't look good in an array called @number, so we can use splice to remove them:

@capture = splice( @number, 1, 3, ());

But now we have a gap in our number sequence:

@capture = splice( @number, 1, 0, qw(one two three));

The length argument determines what is removed from your array. You can think of offset as the array index. -1 in the offset starts our alterations something from the end of the array, just as @myarray1] will index the last element of any array.


 
 file32.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 @number = qw(zero one two three four five six seven eight nine ten);
 
 @capture = splice( @number, 1, 3, qw(alpha beta charlie) );
 
 print "\@capture ==>@capture \n\@number==> @number\n"; 
 @capture = splice( @number, 1, 3, () );
 print "\@capture ==>@capture \n\@number==> @number\n"; 
 
 @capture = splice( @number, 1, 0, qw(one two three) );
 print "\@capture ==>@capture \n\@number==> @number\n"; 
 

We can arrange the order of lists with the reverse and sort functions.
@array = reverse LIST; Whatever the order of the list, it is returned to an array in reverse order.
@backwardnumbers = reverse qw(one two three four five six seven eight nine ten); More extensive ordering of a list can be accomplished with sort. At it's simplest, sort orders a list according to the ASCII code order of the character in of the elements in a list. This can look funny when sorting numbers above the number 9.

sort is actually a very complex function which can act as its own little user defined function. In addition to a simple sort, sort can take a block, similarly as for does, and sorts the list in the array according to instructions in the block. For example:


 
 file33.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 @numbers = sort qw(10 9 8 7 6 5 4 3 2 1 20 30 21 22 44 15);
 
 print "\@numbers ==>@numbers\n";
 
 @numbers = sort {$a <=> $b} qw(10 9 8 7 6 5 4 3 2 1 20 30 21 22 44 15);
 print "\@numbers ==>@numbers\n";
 
 @numbers = sort {$b <=> $a} qw(10 9 8 7 6 5 4 3 2 1 20 30 21 22 44 15);
 print "\@numbers ==>@numbers\n";
 
 @names = sort {$a cmp $b} qw(Frank Elvin David Charlie Bobby Alfred);
 print "\@names ==>@names\n";
 
 @names = sort {$b cmp $a} qw(Go Frank Elvin David Charlie Bobby Alfred);
 print "\@names ==>@names\n";
 
 @names = sort {length($b) <=> length($a)} qw(Go Frank Elvin David Charlie Bobby Alfred);
 print "\@names ==>@names\n";
 
 @names = sort {
         if ($a eq "Elvin"){
                 return 1;
         }else{
                 length($a) <=> length($b);
         }
 } qw(Go Frank Elvin David Charlie Bobby Alfred);
 print "\@names ==>@names\n";
 

When the block returns a -l, $a is sorted as being first (or at the the beginning) and when it returns a +1, the order of the two elements being compared is reversed. Instead of a block, sort can also take a simple subroutine with $a and $b automatically being passed as global system variables. See perldoc -f sort for more details on using functions with sort.

Some functions behave differently for lists than when scalars are used as parameters for them. The print function also treats arrays differently than one would expect. It preformats the elements of the array for your convince under certain conditions.
print @myarray; prints all the array elements one after the other without format. print "@myarray" puts a space between elements. If you try to concatenate the array with a . operator or followed by a string, then you are forcing the scalar value of @myarray, and causing it to return the size of the array. The function scalar forces the array into scalar context. Remember, however, that functions are not interpolated in double quotes


 
 file34.pl.html
 
 
 
 #!/usr/bin/perl
 
 @numbers = qw(one two three four five six seven eight nine ten);
 print "just printing the array raw\n";
 print @numbers;
 print "print array in quotes\n";
 print "@numbers";
 
 
 



Revisiting for and foreach

for and foreach have the basic structure of:

for $tmp (@some_array_or_list){ statements in block; .... } These control flow constructions are largely designed to be used with arrays. Let's look at some specific examples of for loop constructs using arrays. All for and foreach constructs need parenthesis. If it contains just a list, then the list can be included within the parentheses as normal.

for $tmp (@myarray){}

or

for $tmp ("one", "two", "three"){};

The user defined variable which is used in the for construction is more than just assigned the value of the list elements. It actually is an alias for the real variable. Changing the user defined variable within the loop causes the element within the variable to also change.

@myarray = (1..10);
for $tmp (@myarray){
	$tmp++;
}
print "@myarray \n";
This construction raises all the elements of the array by one. Try this program for a review of the concept of this section until now:

 
 file35.pl.html
 
 
 
 #!/usr/bin/perl -w
 use diagnostics;
 
 $line = "_"x80;
 $passage = "In the beginning God created heaven and earth.  And the Earth was void and in chaos."; #no \n
 print "$passage\n";
 
 @vocal = split /\s+/, $passage;
 print "0: ";
 print sort(@vocal);# doesn't space of print a linefeed 
 print "\n"; #clear the line
 
 print "1: ";
 print sort @vocal . "\n";# doesn't work. print forces @vocal to scalar due to the dot operator
 print "2: ";
 print sort(@vocal)  . "\n";# doesn't work. dot can't concat array and string
  
 print "3: ";
 print "sort(@vocal)" . "\n"; #fails  - functions can not be seen in double quotes
 
 print "4: ";
 
 print (sort(@vocal),"\n"); #works because we forces print to see a list
 print "5: ";
 print (sort(@vocal)) . "\n"; #doesn't work - The sort works, but the dot can not be cancatinated a list
 
 for $tmp (sort(@vocal)){
         print "$tmp\n";
 }
 print "$line\n";
 for $tmp (split /\.?\s+/, $passage){
         print "$tmp\n";
 }
 print "$line\n";
 for $tmp (@vocal){
         print "$tmp\n";
 }
 print "$line\n";
 @myarray = (1..10);
 for $tmp (@myarray){
         $tmp++;
 }
 print "@myarray \n";
 



References of Scalars and Arrays

Perl variables can have be pointed to by other variables. This probably seems like a difficult thing to understand. To begin understanding it, let's look at the following program:


 
 file36.pl.html
 
 
 
 #!/usr/bin/perl
 
 #Refrence examples
 
 $name = "Ruben I Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1976";
 $maritial_status = "married";
 
 print "$name\n$address\n$city, $state $zipcode\n";
 
 $ref_name = \$name;
 print "$ref_name \n";
 print "${$ref_name} \n";
 
 

In this example, we have populated a series of scalar variables is information which essentially forms a single record. The scalar $name contains the string "Ruben I Safir". When we print $name - that value is sent to STDOUT. When we create the variable $ref_name, we do not assign it the value "Ruben I Safir", as it is stored in the scalar $name. Instead, we are assigning information needed to find the value stored with name. The value itself is stored only once.

The mechanism used to extract the information to reference the value of $name is by putting a backslash in front of the variable containing the information.

$ref_name = \$name; Once the reference is store in the scalar $ref_name, we can access the value through $ref_name by by dereferencing it as follows:

${$ref_name}

As you recall, we said that all curly braces return something to its external enviorment. When used with references, they return the reference, and then that reference is interpreted by the outside enviorment. The proper interpretation of the return value of the array is dependent on the symbol in front of the curly brace, in this case, a $.

Whole arrays can be carried around in a single scalar variable as a reference to an array:


 
 file37.pl.html
 
 
 
 #!/usr/bin/perl
 
 #Refrence examples
 
 $name = "Ruben I Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1976";
 $maritial_status = "married";
 
 @record = ($name, $address, $city, $state, $zipcode, $datofbirth, $martial_status);
 
 $ref_array = \@record;
 print "The array:\n@record\n";
 print "The reference to an array ==> $ref_array\n";
 print "The dereferenced array:\n@{$ref_array}\n";
 print "One element of the aray through reference==> ${$ref_array}[0]\n";
 
 
 

Notice that the value of $ref_rec says array, not scalar. To dereference it we need to use a @ symbol, instead of a $ symbol. But it can be evaluated element by element just like a regular array. We will learn more about references as we continue and at the end of this section.



Associative Arrays and Hashes

In addition to the array list variable, perl also has a highly useful data construct for lists called the associative array, commonly referred to as a hash. Hashes are wonderful things and perform lot's of magic for the perl programmer. The essential syntax of the hash is:

%myhash = qw(Some list with an even number of words); $myscalar = $myhash{'Some'}; #This returns the string 'list';

Notice that our friends, the curly braces, shows up for the party again.

Hashes store data as pairs: key-value.


 
 file38.pl.html
 
 
 
 #!/usr/bin/perl
 
 #Refrence examples
 
 $name = "Ruben I Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1976";
 $maritial_status = "married";
 
 $record = join "\t",($name, $address, $city, $state, $zipcode, $datofbirth, $martial_status);
 $record .= "\n";
 
 print "$record";
 $cards{$name} = $record;#create a hash with one argument
 
 
 
 $name = "Ellen A Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1973";
 $maritial_status = "married";
 
 
 $record = join "\t",($name, $address, $city, $state, $zipcode, $datofbirth, $martial_status);
 $record .= "\n";
 $cards{$name} = $record;#create a hash with one argument
 
 print "$cards{'Ruben I Safir'}\n";
 print "$cards{'Ellen A Safir'}\n";
 

This can be very powerful for the creation of databases and structured records. You can use a for loop to swing through your records. Doing this as you would an array would not be very useful. It would just act as an array, and convert to a flat list. Perl gives us a few list operators to help us deal with hash structures: keys, values, each. keys and values return scalar values of the appropriate element of the hash. each returns a list of (key,value). You should try to use it in a list context to prevent unexpected behavior (assign it to an array instead of a scalar). It's best to use each in a while loop rather than a for. In a for loop, the each feeds a list of 2 elements, value and key, and then stops. Try this program for example.


 
 file39.pl.html
 
 
 
 #!/usr/bin/perl -w
 use diagnostics;
 
 #Refrence examples
 
 $name = "Ruben I Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1976";
 $maritial_status = "married";
 
 $record = join "\t",($name, $address, $city, $state, $zipcode, $datofbirth, $martial_status);
 $record .= "\n";
 
 print "$record";
 $cards{$name} = $record;#create a hash with one argument
 
 
 
 $name = "Ellen A Safir";
 $address = "345 East 24th Street";
 $city = "Brooklyn";
 $state = "New York";
 $zipcode = "11236";
 $dateofbirth="July 4th 1973";
 $maritial_status = "married";
 
 
 $record = join "\t",($name, $address, $city, $state, $zipcode, $datofbirth, $martial_status);
 $record .= "\n";
 $cards{$name} = $record;#create a hash with one argument
 
 #print out the keys of our catelogue
 
 for $tmp (keys %cards){
         print "Keys: $tmp\n";
 }
 
 #print out the values of our catelogue
 
 for $tmp (values %cards){
         print "Values: $tmp\n";
 }
 #print out the both of our catelogue
 
 #for $tmp(each %cards){
 #       print "each in for: $tmp\n";
 #}#WORKS ONLY ONES
 
 while(@pair = each %cards){
         print "Key in while: $pair[0]\n";
         print "Value in while: $pair[1]\n";
 }
 

Be ware that each will call the next index in the hash each time it is called. This is true within a loop or anywhere else in a program until all of the hash is done being evaluated by each. When looping through a hash the order in which the pairs are tapped is random. You can not make assumptions about the order that the data is stored.

One last thing... don't try to assign new elements into a hash which it is being evaluated by each, keys or values. You can introduce instability into your program.



SCOPE

Until now, everywhere we create a variable, that variable has been available over the complete program. As a general practice, this is not the best of programming technique. Recall that when we create a scalar, or a hash, or an array, we said that the name of that variable gets stored internally in perl to a symbols table which we can access through the typeglob *mysymbol. We will now expand on this.

All the typeglobs in Perl are actually stored in a hash whose name is the name of your namespace. A namespace can generally be considered, for this discussion, a named area in a Perl program which contains a viewable symbols table. The default namespace is called main. In a sense, when we create a variable without declaring any scope for it we actually create an entry in the main symbol table which looks like this:

$main::myscalar

We can change the current namespace in our program by using the package keyword. If we say

package newspace;

All the variables that existed in main, with a few exceptions, are now out of scope of our program. If we want to then use them, we need to call them with an explicit call to main such as demonstrated above.

Just as variables are scoped within namespaces, they can also be scoped within sections of a namespace. Anytime we are presented with a block, we have an area of memory where we can specify locally scoped variables. We do this with too new key words: my and local. Using these too keywords, we have 3 levels of scope. Outside of our namespace, inside of our namespace and internal to specific blocks

my is a keyword which is a list operator. It takes any number of arguments within parentheses. The parenthesis represent a list. my declares variables and places then in the scope of the curly braces which contain the my variable. A my scoped variable is not entered in the system table of the package. This kind of scoping with my is called lexically scoped variables.


 
 file40.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 $i = 5;
 my($k) = 15;
 print "$main::i\n";
 {
     my ($j)=10;
     print "$main::j\n";#undefind scope in curly braces and lex scpoed with my
     print "$j\n";
 }
 
 #printout symbol table for main.   Notice *k is not in the table.
 
 for $tmp (%main::){
     print "SYMBOL: $tmp\n";
 }
 

local also scopes a variable within curly braces. local, however, does create an entry in the global symbol table of the name space. But it pushed the value of the symbol out of view and temporarily replaces the value to the new value it is given within local the local scope. After the program returns to it's local scope, the original value returns.


 
 file41.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 $i = 5;
 
 {
     local $i = 10;
     local $j = 10;
     print "$main::i\n";
     print "$i\n";
     print "$main::j\n";
     print "$j\n";
 }
 
 #print out symbol table for main
 
 for $tmp (%main::){
     print "SYMBOL: $tmp \n";
     print "SCALAR: $$tmp \n";
 }
 

The last 4 line of this program print out the contents of the package main's symbol table. The notation $PACKAGE::VARIABLE allows us access to the scalar variables located with in a package without changing the default namespace for our program. Since main is our default package, we can access it's variables the hard way using this notation. If we want to access packages from an external package, then first we need to use the keyword use as in the following example:


 
 file42.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 use Text::Wrap;
 
 print "The number of columns to wrap is $Text::Wrap::columns \n";
 
 

We will be coming back to the discussion of packages in more detail at the end of this course.



Typeglobs

Typeglob represent an entry in the a packages symbol table and allow direct access to a package's symbol table. We can assign one typeglob to another, and then all the variable types between the two tables point to the same values. If you alter the values of one symbol, the other symbol is also changed because they are pointing at the same data. This assignment of typeglobs is similar to passing of references, and predates references in Perl. It is used less today because we have true references. However, it still has some unique uses.


 
 file43.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 $first = "The Meek will inherit the earth.";
 @first = qw(The Meek will inherit the earth.);
 %first = qw(mammal dog bird parot reptile turtle plant oak);
 
 *second = *first;
 
 print "Scalar $second \n";
 
 for $tmp (@second){
         print "Element of an array $tmp\n";
         $tmp = "changed!";
         }
 for $key (keys %second){
         print "Hash Key: $key\nHash Value $second{$key}\n";
         }
 #Change one and the other changes
         
 for $tmp (@first){
         print "Element of an array $tmp\n";
 }
 

The entry's in each typeglob include the following represented data constructions within it.

Filehandles, unlike other data constructions, can not be scoped with my. They can have local scope. Remember that local creates a new symbol table entry in a package name space. my scoped variables do not become part of the namespaces symbol table, and is completely scoped within it's curly braces or the package. To pass filehandles around we need to manipulate typeglobs. The need to do this does not often arise.


 
 file44.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 print "\nOpen the password file on you system and print 5 entries.\n\n";
 
 my $i = 0;
 
 open PASS, "/etc/passwd";
 while(<PASS>){
         print "$_";
         last if ++$i > 4;
 }
 
 print "\nOpen the group file on your system and print it.\n\n";
 
 GROUP:{
               local *PASS; #push the global value out
                 #of the way and create a local new value
               open PASS, "/etc/group";
               while(<PASS>){
                       print "$_";
               }
       }
 
 #Print password again      
 
 print "\nPrint the rest of /ect/passwd \n\n"; 
 while(<PASS>){
         print "$_";
 }
 

Filehandles, despite being in the symbols table, and passable with typeglobs, have an odd behavior when the typeglob itself is passed around are references. The standardized way of referencing and dereferencing doesn't work with Filehandles. For example we have the references:

$refsc = \$myscalar; creates a reference to a scalar.
print{$$refscalar); dereferences the scalar.

$refar = \@myarray; creates a reference to an array.
@new_array = @$refar; dereferences the array.

$refha = \%myhash; creates a reference to a hash.
%new_hash = %$refha; dereferences the hash.

But Filehandles have no symbol to use. So, if we pass the entire reference of a typeglob to a scoped part of our program, the entire referenced typeglob magically derefences for us as a filehandle. Programmers who are first learning would not often do this. But you can store this away in the back of your mind for the future

open symbol, ">/tmp/test" or die $!;

{
my $ref_glob = \*ssymbol;
print $ref_glob "This is my Test\n";
}
As we showed, typeglobs also can be referenced, for whatever reason one would want to do this like scalars -

$refglob = \*mytypeglob;

This can be odd. The following program displays some expected behavior:


 
 file45.pl.html
 
 
 
 #!/usr/bin/perl -w
 
 $name = "Ruben I Safir";
 @name = qw(Esther Sara Rachel Chana Shoshona Leah);
 %name = qw(Abraham Sara Issac Rebecca Jacob Leah);
 
 $syms = \*name;
 
 print "$syms\n";
 print "${*$syms}\n";
 print "@{*$syms}\n";
 
 for $tmp (keys %{*$syms}){
         print "KEY: $tmp VALUE ${*$syms}{$tmp}\n";
 }
 

Each section here is dereferencing the referenced variable as a typeglob and using it as a regular typeglob would be used. Here we are forcing it to be dereferenced as a typeglob with the expression {*$sym}, which can be thought of as *{$sym}. Curly braces are usually optional with dereferencing but almost always helpful to understand what is happening

Normally with typeglobs, if we pass them or alias them, we can deference them without and fancy notation. For example:


 
 file46.pl.html
 
 
 
 #!/usr/bin/perl -w
 use diagnostics;
 
 $name = "Ruben I Safir";
 @name = qw(Esther Sara Rachel Chana Shoshona Leah);
 %name = qw(Abraham Sara Issac Rebecca Jacob Leah);
 
 *nomes = *name;
 
 print "$nomes\n";
 #print "@nomes \n"; print trick doesn't work for alias
 
 print @nomes;
 print "@name \n";
 for $tmp (keys %nomes){
         print "KEY: $tmp VALUE $nomes{$tmp}\n";
 }
 
 

If we try to do this similarly with the reference, we don't get the expected behavior. This enters into an area of poorly documented behavior in perl.


 
 file47.pl.html
 
 
 
 #!/usr/bin/perl -w
 use diagnostics;
 
 $name = "Ruben I Safir";
 @name = qw(Esther Sara Rachel Chana Shoshona Leah);
 %name = qw(Abraham Sara Issac Rebecca Jacob Leah);
 
 $nomes = \*name;
 
 print "$nomes\n";
 print "$$nomes \n"; 
 
 print "@{$$nomes}\n";
 for $tmp (keys %$$nomes){
         print "KEY: $tmp VALUE $$$nomes{$tmp}\n";
 }
 
 

The cause for all this odd behavior is that typeglobs are themselves really a complex internal data construction that are not often used in real code. When discussing a typeglob, we are really talking about a reference entry in the namespaces symbol table. Typeglobs immediately dereference in normal code by replacing the * with a $,@,%, etc. For any typeglob defined as *symbol, the scalar for that typeglob is automatically accessed as $symbol, the array @symbol, and so on.

Typeglobs have a dual nature in that they also emulate hashes to the internal datatypes.

Once you understand this dual nature of typeglobs, then you realize that $ref_glob = /*symbol is a strange bird indeed and is implemented at the Perl developers convenience since it can't really behave according to the rules of references.

NEXT: Structured  Programming and Subroutines