Chapter 5

FuNCtions


CONTENTS

This chapter takes a look at fuNCtions. FuNCtions are blocks of codes that are given names so that you can use them as needed. FuNCtions help you to organize your code into pieces that are easy to understand and work with. They let you build your program step by step, testing the code along the way.

After you get the idea for a program, you need to develop a program outline-either in your head or on paper. Each step in the outline might be one fuNCtion in your program. This is called modular programming. Modular programming is very good at allowing you to hide the details so that readers of your source code can understand the overall aim of your program.

For instaNCe, if your program has a fuNCtion that calculates the area of a circle, the following line of code might be used to call it:


$areaOfFirstCircle = areaOfCircle($firstRadius);

By looking at the fuNCtion call, the reader knows what the program is doing. Detailed understanding of the actual fuNCtion is not needed.

Tip
Well thought out fuNCtion and variable names help people to understand your program. If the line of code was
$areaFC = areaCirc($fRad);
its meaning would not be as clear.

Note
Calling a fuNCtion means that Perl stops executing the current series of program lines. Program flow jumps into the program code inside the fuNCtion. When the fuNCtion is finished, Perl jumps back to the point at which the fuNCtion call was made. Program execution continues from that point onward.

Let's look at the fuNCtion call a little closer. The first thing on the line is a scalar variable and an assignment operator. You already know this means Perl assigns the value on the right of the assignment operator to $areaOfFirstCircle. But, what exactly is on the right?

The first thing you see is the fuNCtion name areaOfCircle(). The parentheses directly to the right and no $, @, or % beginning the name indicates that this is a fuNCtion call. Inside the parentheses is a list of parameters or values that get passed to the fuNCtion. You can think of a parameter just like a football. When passed, the receiver (for example, the fuNCtion) has several options: run (modify it in some way), pass (call other routines), fumble (call the error handler).

Note
Perl enables you to use the & character to start fuNCtion names, and in a few cases it is needed. Those few situations that the & character is needed are beyond the scope of this book.

Listing 5.1 shows a short program that calls and defines the areaOfCircle() fuNCtion.

Assign $areaOfFirstCircle the value that is returned by the fuNCtionareaOfCircle().
Print
$areaOfFirstCircle.
Define the areaOfCircle() fuNCtion.
Get the first parameter from the
@_ parameter array.
Calculate the area and return the new value.

Listing 5.1  05LST01.PL-Calculating the Area of a Circle

$areaOfFirstCircle = areaOfCircle(5);

print("$areaOfFirstCircle\n");



sub areaOfCircle {

    $radius = $_[0];

    return(3.1415 * ($radius ** 2));

}


This program prints:


78.7375

The fact that something prints tells you that the program flow returned to the print line after calling the areaOfCircle() fuNCtion.

A fuNCtion definition is very simple. It consists of:


sub fuNCtionName {

}

That's it. Perl fuNCtion definitions never get any more complex.

The complicated part comes when dealing with parameters. Parameters are values passed to the fuNCtion (remember the football?). The parameters are specified inside the parentheses that immediately follow the fuNCtion name. In Listing 5.1, the fuNCtion call was areaOfCircle(5). There was only one parameter, the number 5. Even though there is only one parameter, Perl creates a parameter array for the fuNCtion to use.

Inside the areaOfCircle() fuNCtion, the parameter array is named @_. All parameters specified during the fuNCtion call are stored in the @_ array so that the fuNCtion can retrieve them. Our small fuNCtion did this with the line:


$radius = $_[0];

This line of code assigns the first element of the @_ array to the $radius scalar.

Note
Because parameters always are passed as lists, Perl fuNCtions also are referred to as list operators. And, if only one parameter is used, they are sometimes referred to as unary operators. However, I'll continue to call them fuNCtions and leave the finer points of distiNCtion to others.

The next line of the fuNCtion:


return(3.1415 * ($radius ** 2));

calculates the circle's area and returns the newly calculated value. In this case, the returning value is assigned to the $areaOfFirstCircle scalar variable.

Note
If you prefer, you don't need to use the return() fuNCtion to return a value because Perl automatically returns the value of the last expression evaluated. I prefer to use the return() fuNCtion and be explicit so that there is no mistaking my intention.

You may have used programming languages that distinguish between a fuNCtion and a subroutine, the differeNCe being that a fuNCtion returns a value and a subroutine does not. Perl makes no such distiNCtions. Everything is a fuNCtion-whether or not it returns a value.

Example: Using the Parameter Array (@_)

All parameters to a fuNCtion are stored in an array called @_. One side effect of this is that you can find out how many parameters were passed by evaluating @ in a scalar context.

Call the firstSub() fuNCtion with a variety of parameters.
Define the
firstSub() fuNCtion
Assign
$numParameters the number of elements in the array @_.
Print out how any parameters were passed.

firstSub(1, 2, 3, 4, 5, 6);

firstSub(1..3);

firstSub("A".."Z");



sub firstSub {

    $numParameters = @_ ;

    print("The number of parameters is $numParameters\n");

}

This program prints out:


The number of parameters is 6

The number of parameters is 3

The number of parameters is 26

Perl lets you pass any number of parameters to a fuNCtion. The fuNCtion decides which parameters to use and in what order. The @_ array is used like any other array.

Let's say that you want to use scalar variables to refereNCe the parameters so you don't have to use the clumsy and uninformative $_ [0] array element notation. By using the assignment operator, you can assign array elements to scalars in one easy step.

Call the areaOfRectangle() fuNCtion with varying parameters.
Define the
areaOfRectangle() fuNCtion.
Assign the first two elements of
@_ to $height and $width respectively.
Calculate the area.
Print the three variables:
$height, $width, and $area.

areaOfRectangle(2, 3);

areaOfRectangle(5, 6);



sub areaOfRectangle {

    ($height, $width) = @_ ;



    $area = $height * $width;



    print("The height is $height. The width is $width.

        The area is $area.\n\n");

}

This program prints out:


The height is 2. The width is 3.

        The area is 6.



The height is 5. The width is 6.

        The area is 30.

The statement ($height,$width) = @_; does the array element to scalar assignment. The first element is assigned to $height, and the second element is assigned to $width. After the assignment is made, you can use the scalar variables to represent the parameters.

Example: Passing Parameters by RefereNCe

Using scalar variables inside your fuNCtions is a good idea for another reason-besides simple readability coNCerns. When you change the value of the elements of the @ array, you also change the value of the parameters in the rest of the program. This is because Perl parameters are called by refereNCe. When parameters are called by refereNCe, changing their value in the fuNCtion also changes their value in the main program. Listing 5.2 shows how this happens.

Create an array with 6 elements.
Print the elements of the array.
Call the
firstSub() fuNCtion.
Print the elements of the array.
Define the
firstSub() fuNCtion.
Change the values of the first two elements of
@_.

Listing 5.2  05LST02.PL-Using the @Array to Show Call by RefereNCe

@array = (0..5);

print("Before fuNCtion call, array = @array\n");

firstSub(@array);

print("After fuNCtion call, array =  @array\n");



sub firstSub{

    $_[0] = "A";

    $_[1] = "B";

}


This program prints:


Before fuNCtion call, array =  0 1 2 3 4 5

After fuNCtion call, array =   A B 2 3 4 5

You can see that the fuNCtion was able to affect the @array variable in the main program. Generally, this is considered bad programming practice because it does not isolate what the fuNCtion does from the rest of the program. If you change the fuNCtion so that scalars are used inside the fuNCtion, this problem goes away. List-ing 5.3 shows how to redo the program in Listing 5.2 so scalars are used inside the fuNCtion.

Create an array with 6 elements.
Print the elements of the array.
Call the
firstSub() fuNCtion.
Print the elements of the array.
Define the
firstSub() fuNCtion.
Assign the first two elements of
@_ to $firstVar and $secondVar.
Change the values of the scalar variables.

Listing 5.3  05LST03.PL-Using Scalars Instead of the @_ Array Inside FuNCtions

@array = (0..5);

print("Before fuNCtion call, array = @array\n");

firstSub(@array);

print("After fuNCtion call, array =  @array\n");



sub firstSub{

    ($firstVar, $secondVar) = @_ ;



    $firstVar = "A";

    $secondVar = "B";

}


This program prints:


Before fuNCtion call, array =  0 1 2 3 4 5

After fuNCtion call, array =   0 1 2 3 4 5

This example shows that the original @array variable is left untouched. However, another problem has quietly arisen. Let's change the program a little so the values of $firstVar are printed before and after the fuNCtion call. Listing 5.4 shows how changing a variable in the fuNCtion affects the main program.

Assign a value to $firstVar.
Create an array with 6 elements.
Print the elements of the array.
Call the
firstSub() fuNCtion.
Print the elements of the array.
Define the
firstSub() fuNCtion.
Assign the first two elements of
@_ to $firstVar and $secondVar.
Change the values of the scalar variables.

Listing 5.4  05LST04.PL-Using Variables in FuNCtions Can Cause Unexpected Results

$firstVar = 10;

@array    = (0..5);



print("Before fuNCtion call\n");

print("\tfirstVar = $firstVar\n");

print("\tarray    = @array\n");



firstSub(@array);



print("After fuNCtion call\n");

print("\tfirstVar = $firstVar\n");

print("\tarray    = @array\n");



sub firstSub{

    ($firstVar, $secondVar) = @_ ;



    $firstVar = "A";

    $secondVar = "B";

}


This program prints:


Before fuNCtion call

        firstVar = 10

        array    = 0 1 2 3 4 5



After fuNCtion call

        firstVar = A

        array    = 0 1 2 3 4 5

By using the $firstVar variable in the fuNCtion you also change its value in the main program. By default, all Perl variables are accessible everywhere inside a program. This ability to globally access variables can be a good thing at times. It does help when trying to isolate a fuNCtion from the rest of your program. The next section shows you how to create variables that can only be used inside fuNCtions.

Example: Scope of Variables

Scope refers to the visibility of variables. In other words, which parts of your program can see or use it. Normally, every variable has a global scope. ONCe defined, every part of your program can access a variable.

It is very useful to be able to limit a variable's scope to a single fuNCtion. In other words, the variable wil have a limited scope. This way, changes inside the fuNCtion can't affect the main program in unexpected ways. Listing 5.5 introduces two of Perl's built-in fuNCtions that create variables of limited scope. The my() fuNCtion creates a variable that only the current fuNCtion can see. The local() fuNCtion creates a variable that fuNCtions the current fuNCtion calls can see. If that sounds confusing, don't worry. It is confusing; but, Listing 5.5 should clear things up. In this case, it's a listing that is worth a thousand words, not a picture!

Call firstSub() with a two parameters.
Define the
firstSub() fuNCtion.
Assign the first parameter to local variable
$firstVar.
Assign the second parameter to my variable
$secondVar.
Print the variables.
Call the second fuNCtion without any parameters.
Print the variables to see what changed.
Define the
secondSub() fuNCtion.
Print the variables.
Assign new values to the variables.
Print the variables to see that the new values were assigned correctly.

Listing 5.5  05LST05.PL-Using the Local and My FuNCtions to Create Local Variables

firstSub("AAAAA", "BBBBB");



sub firstSub{

    local ($firstVar) = $_[0];

    my($secondVar)    = $_[1];



    print("firstSub: firstVar  = $firstVar\n");

    print("firstSub: secondVar = $secondVar\n\n");



    secondSub();



    print("firstSub: firstVar  = $firstVar\n");

    print("firstSub: secondVar = $secondVar\n\n");

}



sub secondSub{

    print("secondSub: firstVar  = $firstVar\n");

    print("secondSub: secondVar = $secondVar\n\n");



    $firstVar  = "ccccC";

    $secondVar = "DDDDD";



    print("secondSub: firstVar  = $firstVar\n");

    print("secondSub: secondVar = $secondVar\n\n");

}


This program prints:


firstSub: firstVar = AAAAA

firstSub: secondVar = BBBBB



secondSub: firstVar  = AAAAA

Use of uninitialized value at test.pl line 19.

secondSub: secondVar =



secondSub: firstVar  = ccccC

secondSub: secondVar = DDDDD



firstSub: firstVar  = ccccC

firstSub: secondVar = BBBBB

The output from this example shows that secondSub() could not access the $secondVar variable that was created with my() inside firstSub(). Perl even prints out an error message that warns about the uninitialized value. The $firstVar variable, however, can be accessed and valued by secondSub().

Tip
It's generally a better idea to use my() instead of local() so that you can tightly control the scope of local variables. Think about it this way-it's 4:00 in the morning and the project is due. Is that the time to be checking variable scope? No. Using my()enforces good programming practices and reduces headaches.

Actually, the my() fuNCtion is even more complex than I've said. The easy definition is that it creates variables that only the current fuNCtion can see. The true definition is that it creates variables with lexical scope. This distiNCtion is only important when creating modules or objects, so let's ignore the complicated definition for now. You'll hear more about it in Chapter 15, "Perl Modules."

If you remember, I mentioned calling parameters by refereNCe. Passing parameters by refereNCe means that fuNCtions can change the variable's value, and the main program sees the change. When local() is used in conjuNCtion with assigning the @_ array elements to scalars, then the parameters are essentially being called by value. The fuNCtion can change the value of the variable, but only the fuNCtion is affected. The rest of the program sees the old value.

Example: Using a List as a FuNCtion Parameter

Now that you understand about the scope of variables, let's take another look at parameters. Because all parameters are passed to a fuNCtion in one array, what if you need to pass both a scalar and an array to the same fuNCtion? This next example shows you what happens.

Call the firstSub() fuNCtion with two parameters: a list and a scalar.
Define the
firstSub() fuNCtion.
Assign the elements of the
@_ array to @array and $firstVar.
Print
@array and $firstVar.

firstSub((0..10), "AAAA");



sub firstSub{

    local(@array, $firstVar) = @_ ;



    print("firstSub: array    = @array\n");

    print("firstSub: firstVar = $firstVar\n");

}

This program prints:


firstSub: array    = 0 1 2 3 4 5 6 7 8 9 10 AAAA

Use of uninitialized value at test.pl line 8.

firstSub: firstVar =

When the local variables are initialized, the @array variables grab all of the elements in the @ array, leaving none for the scalar variable. This results in the uninitialized value message displayed in the output. You can fix this by merely reversing the order of parameters. If the scalar value comes first, then the fuNCtion processes the parameters without a problem.

Call the firstSub() fuNCtion with two parameters: a scalar and a list.
Define the
firstSub() fuNCtion.
Assign the elements of the
@_ array to $firstVar and @array.
Print
@array and $firstVar.

firstSub("AAAA", (0..10));



sub firstSub{

    local($firstVar, @array) = @_ ;



    print("firstSub: array    = @array\n");

    print("firstSub: firstVar = $firstVar\n");

}

This program prints:


firstSub: array    = 0 1 2 3 4 5 6 7 8 9 10

firstSub: firstVar = AAAA

Note
You can pass as many scalar values as you want to a fuNCtion, but only one array. If you try to pass more than one array, the array elements become joined together and passed as one array to the fuNCtion. Your fuNCtion won't be able to tell when one array starts and another ends.

Example: Nesting FuNCtion Calls

FuNCtion calls can be nested many levels deep. Nested fuNCtion calls simply means that one fuNCtion can call another which in turn can call another. Exactly how many levels you can nest depends on which version of Perl you are running and how your machine is configured. Normally, you don't have to worry about it. If you want to see how many levels your system can recurse, try the following small program:

Call the firstSub() fuNCtion.
Define the
firstSub() fuNCtion.
Print
$count
INCrement $count by one.
Call the
firstSub() fuNCtion recursively.

firstSub();



sub firstSub{

    print("$count\n");

    $count++;

    firstSub();

}

My system counts up to 127 before displaying the following message:


Error: Runtime exception

While it is important to realize that there is a limit to the number of times your program can nest fuNCtions, you should never run into this limitation unless you are working with recursive mathematical fuNCtions.

Example: Using a Private FuNCtion

Occasionally, you might want to create a private fuNCtion. A private fuNCtion is one that is only available inside the scope where it was defined.

Assign the return value from performCalc() to $temp.
Print
$temp.
Define the
performCalc() fuNCtion.
Assign my scalar variables values from the
@_ parameter array.
Define the private fuNCtion referred to by
$square.
Return the first element of the
@_ parameter array raised to the 2nd power.
Return the value of
$firstVar raised to the 2nd power and
$secondVar raised to the 2nd power.

$temp = performCalc(10, 10);

print("temp = $temp\n");



sub performCalc {

    my ($firstVar, $secondVar) = @_;



    my $square = sub {

        return($_[0] ** 2);

    };



    return(&$square($firstVar) + &$square($secondVar));

};

This program prints:


temp = 200

This example is rather trivial, but it serves to show that in Perl it pays to create little helper routines. A fine line needs to be drawn between what should be iNCluded as a private fuNCtion and what shouldn't. I would draw the line at 5 or 6 lines of code. Anything longer probably should be made into its own fuNCtion. I would also say that a private fuNCtion should have only one purpose for existeNCe. Performing a calculation and then opening a file is too much fuNCtionality for a single private fuNCtion to have.

The rest of the chapter is devoted to showing you some of the built-in fuNCtions of Perl. These little nuggets of fuNCtionality will become part of your arsenal of programming weapons.

String FuNCtions

The first set of fuNCtions that we'll look at are those that deal with strings. These fuNCtions let you determine a string's length, search for a sub-string, and change the case of the characters in the string, among other things. Table 5.1 shows Perl's string fuNCtions.

Table 5.1  String FuNCtions

FuNCtionDescription
chomp(STRING) OR chomp(ARRAY) Uses the value of the $/ special variable to remove endings from STRING or each element of ARRAY. The line ending is only removed if it matches the current value of $/.
chop(STRING) OR chop(ARRAY) Removes the last character from a string or the last character from every element in an array. The last character chopped is returned.
chr(NUMBER) Returns the character represented by NUMBER in the ASCII table. For instaNCe, chr(65) returns the letter A. For more information about the ASCII table see Appendix E, "ASCII Table."
crypt(STRING1, STRING2) ENCrypts STRING1. Unfortunately, Perl does not provide a decrypt fuNCtion.
index(STRING, SUBSTRING, POSITION) Returns the position of the first occurreNCe of SUBSTRING in STRING at or after POSITION. If you don't specify POSITION, the search starts at the beginning of STRING.
join(STRING, ARRAY) Returns a string that consists of all of the elements of ARRAY joined together by STRING. For instaNCe, join(">>", ("AA", "BB", "cc")) returns "AA>>BB>>cc".
lc(STRING) Returns a string with every letter of STRING in lowercase. For instaNCe, lc("ABCD") returns "abcd".
lcfirst(STRING) Returns a string with the first letter of STRING in lowercase. For instaNCe, lcfirst("ABCD") returns "aBCD".
length(STRING) Returns the length of STRING.
rindex(STRING, SUBSTRING, POSITION) Returns the position of the last occurreNCe of SUBSTRING in STRING at or after POSITION. If you don't specify POSITION, the search starts at the end of STRING.
split(PATTERN, STRING, LIMIT) Breaks up a string based on some delimiter. In an array context, it returns a list of the things that were found. In a scalar context, it returns the number of things found.
substr(STRING, OFFSET, LENGTH) Returns a portion of STRING as determined by the OFFSET and LENGTH parameters. If LENGTH is not specified, then everything from OFFSET to the end of STRING is returned. A negative OFFSET can be used to start from the right side of STRING.
uc(STRING) Returns a string with every letter of STRING in uppercase. For instaNCe, uc("abcd") returns "ABCD".
Ucfirst(STRING) Returns a string with the first letter of STRING in uppercase. For instaNCe, ucfirst("abcd") returns "Abcd".

Note
As a general rule, if Perl sees a number where it expects a string, the number is quietly converted to a string without your needing to do anything.

Note
Some of these fuNCtions use the special variable $_ as the default string to work with. More information about $_ can be found in Chapter 9 "Using Files," and Chapter 12, "Using Special Variables."

The next few sections demonstrate some of these fuNCtions. After seeing some of them work, you'll be able to use the rest of them.

Example: Changing a String's Value

Frequently, I find that I need to change part of a string's value, usually somewhere in the middle of the string. When this need arises, I turn to the substr() fuNCtion. Normally, the substr() fuNCtion returns a sub-string based on three parameters: the string to use, the position to start at, and the length of the string to return.

Assign $firstVar the return value from substr().
Print
$firstVar.

$firstVar = substr("0123BBB789", 4, 3);

print("firstVar  = $firstVar\n");

This program prints:


firstVar = BBB

The substr() fuNCtion starts at the fifth position and returns the next three characters. The returned string can be printed like in the above example, as an array element, for string coNCatention, or any of a hundred other options.

Things become more interesting when you put the substr() fuNCtion on the left-hand side of the assignment statement. Then, you actually can assign a value to the string that substr() returns.

Initialize $firstVar with a string literal.
Replace the string returned by the
substr() fuNCtion with "AAA".
Print
$firstVar.

$firstVar = "0123BBB789";

substr($firstVar, 4, 3) = "AAA";

print("firstVar  = $firstVar\n");

This program prints:


firstVar = 0123AAA789

Example: Searching a String

Another useful thing you can do with strings is search them to see if they have a given sub-string. For example if you have a full path name such as "C:\\WINDOWS \\TEMP\\WSREWE.DAT", you might need to extract the file name at the end of the path. You might do this by searching for the last backslash and then using substr() to return the sub-string.

Note
The path name string has double backslashes to indicate to Perl that we really want a backslash in the string and not some other escape sequeNCe. You can read more about escape sequeNCes in Chapter 2 "Numeric and String Literals."

Assign a string literal to $pathName.
Find the location of the last backslash by starting at the end of the string and working backward using the
rindex() fuNCtion. When the position of the last backslash is found, add one to it so that
$position points at the first character ("W") of the file name.
Use the
substr() fuNCtion to extract the file name and assign it
to
$fileName.
Print
$fileName.

$pathName = "C:\\WINDOWS\\TEMP\\WSREWE.DAT";

$position = rindex($pathName, "\\") + 1;

$fileName = substr($pathName, $position);

print("$fileName\n");

This program prints:


WSREWE.DAT

If the third parameter-the length-is not supplied to substr(), it simply returns the sub-string that starts at the position specified by the second parameter and continues until the end of the string specified by the first parameter.

Array FuNCtions

Arrays are a big part of the Perl language and Perl has a lot of fuNCtions to help you work with them. Some of the actions arrays perform iNClude deleting elements, checking for the existeNCe of an element, reversing all of the the elements in an array, and sorting the elements. Table 5.2 lists the fuNCtions you can use with arrays.

Table 5.2  Array FuNCtions

FuNCtionDescription
defined(VARIABLE) Returns true if VARIABLE has a real value and if the variable has not yet been assigned a value. This is not limited to arrays; any data type can be checked. Also see the exists fuNCtion for information about associative array keys.
delete(KEY) Removes the key-value pair from the given associative array. If you delete a value from the %ENV array, the environment of the current process is changed, not that of the parent.
each(ASSOC_ARRAY) Returns a two-element list that contains a key and value pair from the given associative array. The fuNCtion is mainly used so you can iterate over the associate array elements. A null list is returned when the last element has been read.
exists(KEY) Returns true if the KEY is part of the specified associative array. For instaNCe, exists($array{"Orange"}) returns true if the %array associative array has a key with the value of "Orange."
join(STRING, ARRAY) Returns a string that consists of all of the elements of ARRAY joined together by STRING. For instaNCe, join(">>", ("AA", "BB", "cc")) returns "AA>>BB>>cc".
keys(ASSOC_ARRAY) Returns a list that holds all of the keys in a given associative array. The list is not in any particular order.
map(EXPRESSION, ARRAY) Evaluates EXPRESSION for every element of ARRAY. The special variable $ is assigned each element of ARRAY immediately before EXPRESSION is evaluated.
pack(STRING, ARRAY) Creates a binary structure, using STRING as a guide, of the elements of ARRAY. You can look in Chapter 8 "RefereNCes," for more information.
pop(ARRAY) Returns the last value of an array. It also reduces the size of the array by one.
push(ARRAY1, ARRAY2) Appends the contents of ARRAY2 to ARRAY1. This iNCreases the size of ARRAY1 as needed.
reverse(ARRAY) Reverses the elements of a given array when used in an array context. When used in a scalar context, the array is converted to a string, and the string is reversed.
scalar(ARRAY) Evaluates the array in a scalar context and returns the number of elements in the array.
shift(ARRAY) Returns the first value of an array. It also reduces the size of the array by one.
sort(ARRAY) Returns a list containing the elements of ARRAY in sorted order. See Chapter 8 "RefereNCes," for more information.
splice(ARRAY1, OFFSET, Replaces elements of ARRAY1 with elements
LENGTH, ARRAY2) in ARRAY2. It returns a list holding any elements that were removed. Remember that the $[ variable may change the base array subscript when determining the OFFSET value.
split(PATTERN, STRING, LIMIT) Breaks up a string based on some delimiter. In an array context, it returns a list of the things that were found. In a scalar context, it returns the number of things found.
undef(VARIABLE) Always returns the undefined value. In addition, it undefines VARIABLE, which must be a scalar, an entire array, or a subroutine name.
unpack(STRING, ARRAY) Does the opposite of pack().
unshift(ARRAY1, ARRAY2) Adds the elements of ARRAY2 to the front of ARRAY1. Note that the added elements retain their original order. The size of the new ARRAY1 is returned.
values(ASSOC_ARRAY) Returns a list that holds all of the values in a given associative array. The list is not in any particular order.

As with the string fuNCtions, only a few of these fuNCtions will be explored. ONCe you see the examples, you'll be able to handle the rest with no trouble.

Example: Printing an Associative Array

The each() fuNCtion returns key, value pairs of an associative array one-by-one in a list. This is called iterating over the elements of the array. Iteration is a synonym for looping. So, you also could say that the each() fuNCtion starts at the beginning of an array and loops through each element until the end of the array is reached. This ability lets you work with key, value pairs in a quick easy manner.

The each() fuNCtion does not loop by itself. It needs a little help from some Perl control statements. For this example, we'll use the while loop to print an associative array. The while (CONDITION) {} control statement continues to execute any program code surrounded by the curly braces until the CONDITION turns false.

Create an associative with number, color pairs.
Using a while loop, iterate over the array elements.
Print the key, value pair.

%array = ( "100", "Green", "200", "Orange");



while (($key, $value) = each(%array)) {

      print("$key = $value\n");

}

This program prints:


100 = Green

200 = Orange

The each() fuNCtion returns false when the end of the array is reached. Therefore, you can use it as the basis of the while's condition. When the end of the array is reached, the program continues execution after the closing curly brace. In this example, the program simply ends.

Example: Checking the ExisteNCe of an Element

You can use the defined() fuNCtion to check if an array element exists before you assign a value to it. This ability is very handy if you are reading values from a disk file and don't want to overlay values already in memory. For instaNCe, suppose you have a disk file of customers' addresses and you would like to know if any of them are duplicates. You check for duplicates by reading the information one address at a time and assigning the address to an associative array using the customer name as the key value. If the customer name already exists as a key value, then that address should be flagged for follow up.

Because we haven't talked about disk files yet, we'll need to emulate a disk file with an associative array. And, instead of using customer's address, we'll use customer number and customer name pairs. First, we see what happens when an associative array is created and two values have the same keys.

Call the createPair() fuNCtion three times to create three key, value pairs in the %array associative array.
Loop through
%array, printing each key, value pair.
Define the
createPair() fuNCtion.
Create local variables to hold the key, value pair passed as parameters.
Create an array element to hold the key, value pair.

createPair("100",  "Kathy Jones");

createPair("200",  "Grace Kelly");

createPair("100", "George Orwell");



while (($key, $value) = each %array) {

    print("$key, $value\n");

};



sub createPair{

    my($key, $value) = @_ ;



    $array{$key} = $value;

};

This program prints:


100, George Orwell

200, Grace Kelly

This example takes advantages of the global nature of variables. Even though the %array element is set in the createPair() fuNCtion, the array is still accessible by the main program. Notice that the first key, value pair (100 and Kathy Jones) are overwritten when the third key, value pair is eNCountered. You can see that it is a good idea to be able to determine when an associative array element is already defined so that duplicate entries can be handled. The next program does this.

Call the createPair() fuNCtion three times to create three key, value pairs in the %array associative array.
Loop through
%array, printing each key, value pair.
Define the
createPair() fuNCtion.
Create local variables to hold the key, value pair passed as parameters.
If the key, value pair already exists in
%array, then iNCrement
the customer number by one. Check to see if the new key, value
pair exists. If so, keep iNCrementing until a nonexistent
key, value pair is found.
Create an array element to hold the key, value pair.

createPair("100",  "Kathy Jones");

createPair("200",  "Grace Kelly");

createPair("100", "George Orwell");



while (($key, $value) = each %array) {

    print("$key, $value\n");

};



sub createPair{

    my($key, $value) = @_ ;



    while (defined($array{$key})) {

        $key++;

    }



    $array{$key} = $value;

};

This program prints:


100, George Orwell

101, Kathy Jones

200, Grace Kelly

You can see that the customer number for Kathy Jones has been changed to 101. If the array had already had an entry for 101, the Kathy Jones' new customer number would be 102.

Summary

In this chapter you've learned about fuNCtions-what they are and how to call them. You saw that you can create your own fuNCtion or use one of Perl's many built-in fuNCtions. Each fuNCtion can accept any number of parameters which get delivered to the fuNCtion in the form of the @ array. This array, like any other array in Perl, can be accessed using the array element to access an individual element. ( For instaNCe, $_ [0] accesses the first element in the @ array.) Because Perl parameters are passed by refereNCe, changing the @ array changes the values in the main program as well as the fuNCtion.

You learned about the scope of variables and how all variables are global by default. Then, you saw how to create variable with local scope using local() and my(). My() is the better choice in almost all situations because it enforces local scope and limits side effects from fuNCtion to inside the fuNCtions.

Then you saw that it was possible to nest fuNCtion calls, which means that one fuNCtion can call another, which in turn can call another. You also might call this a chain of fuNCtion calls. Private fuNCtions were introduced next. A private fuNCtion is one that only can be used inside the fuNCtion that defines it.

A list of string fuNCtions then was presented. These iNCluded fuNCtions to remove the last character, eNCrypt a string, find a sub-string, convert array elements into a string, change the case of a string character, and find the length of a string. Examples were shown about how to change a string's characters and how to search a string.

The section on array fuNCtions showed that Perl has a large number of fuNCtions that deal specifically with arrays. The list of fuNCtions iNCluded the ability to delete elements, return key, value pairs from associative arrays, reverse an array's elements, and sort an array. Examples were shown for printing an associative array and checking for the existeNCe of an element.

The next chapter, "Statements," goes into detail about what statements are and how you create them. The information that you learned about variables and fuNCtions will come into play. You'll see how to link variables and fuNCtions together to form expressions and statements.

Review Questions

Answers to Review Questions are in Appendix A.

  1. What is a parameter?
  2. What two fuNCtions are used to create variables with local scope?
  3. What does parameter passing by refereNCe mean?
  4. What is the @_ array used for?
  5. Do Perl variables have global or local scope by default?
  6. Why is it hard to pass two arrays to a fuNCtion?
  7. What is the differeNCe between variables created with local() and variables created with my()?
  8. What does the map() fuNCtion do?

Review Exercises

  1. Create a fuNCtion that prints its own parameter list.
  2. Create a program that uses three fuNCtions to demonstrate fuNCtion call nesting.
  3. Use the chop() fuNCtion in a program. Print both the returned character and the string that was passed as a parameter.
  4. Run the following program to see how many levels of recursion your system configuration supports:

    firstSub();

    sub firstSub{
    print("$count\n");
    $count++;
    firstSub();
    }
  5. Write a fuNCtion that uses the substr() and uc() fuNCtions to change the tenth through twentieth characters to uppercase.
  6. Write a fuNCtion that uses the keys() fuNCtion to print out the values of an associative array.
  7. Create a program that uses a private fuNCtion to subtract two numbers and multiply the result by four.
  8. Write a program that shows what the shift() and unshift() fuNCtions do.
  9. Write a program that shows what the push() and pop() fuNCtions do.