Table of Contents

Subroutines and Parameters

In Perl, subroutines are functions are subroutines. If you like, a subroutine is a user defined function. It's a bit like calling a script a program, or a program a script. For the purposes of this tutorial we'll refer to functions as subroutines, except when we call them functions. Hope that's made the point.

For the purposes of this section we will develop a small program which, by the end, will demonstrate how subroutines work. It also serves to demonstrate how many programs are built, namely a little at a time, in manageable sections. At least, that method works for me. engines.

The chosen theme is gliding. That's aeroplanes without engines. A subject close to every glider pilot's heart is how far they can fly from the altitude they are at. Our program will calculate this. To make it easy we'll assume the air is perfectly calm. Wind would be a complication we don't need, especially when in a crowded lift.

What we need in order to calculate the distance we can fly is:

Obviously input is needed. We can either prompt the user or grab the input from the command line. The latter is easier so we'll just look at @ARGV for the command line parameters. Like so:

($height,$angle)=@ARGV;		# @ARGV is the command line parameters

$distance=$height*$angle;	# an easy calculation

print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

The above should be executed thus:

perl yourscript.pl 5000 24

or whatever your script is called, with whatever parameters you choose to use. I'm a poet and I don't even know it.

That works. What about a slight variation? The pilot does have some control over the glide ratio, for example he can fly faster but at a penalty of a lesser glide ratio. So we should perhaps give a couple of options either side of the given parameters:

($height,$angle)=@ARGV;

$distance=$height*$angle;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle++;			# add 1 to $angle
$distance=$height*$angle;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle-=2;			# subtract 2 from $angle so it is 1 less than the original
$distance=$height*$angle;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

That's cumbersome code. We repeat exactly the same statement. This wastes space, and if we want to change it there are three changes to be made. A better option is to put it into a subroutine:

($height,$angle)=@ARGV;

&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle++;
&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle-=2;
&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

sub howfar {				# sub subroutinename
	$distance=$height*$angle;
}

This is a basic subroutine, and you could stop here and have learnt a very useful technique for programming. Now, when changes are made they are made in one place. Less work, less chances of errors. Improvements can always be made. For example, pilots outside Eastern Europe generally measure height in feet, and glider pilots are usually concerned with how many kilometres they travel over the ground. So we can adapt our program to accept height in feet and output the distance in kilometres:

($height,$angle)=@ARGV;

$height/=3.2;			# divide feet by 3.2 to get metres

&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle++;
&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

$angle-=2;
&howfar;
print "With a glide ratio of $angle:1 you can fly $distance from $height\n";

sub howfar {
	$distance=$height*$angle;
}

When you run this you'll probably get a result which involves a fair few digits after the decimal point. This is messy, and we can fix this by the int function, which in Perl and most other languages returns a number as an integer, ie without those irritating numbers after the decimal point.

You might have also noticed a small bit of Bad Programming Practice slipped into the last example. It was the evil Constant, the '3.2' used to convert feet to metres. Why, I don't hear you ask, is this bad? Surely the conversion will never change?

It won't change, but our use of it might. We may decide that it should be 3.208 instead of 3.2. We may decide to convert from feet to nautical miles instead. You don't know what could happen. Therefore, code with flexibility in mind and that means avoiding constants.

The new improved version with int and constant removed:

($height,$ratio)=@ARGV;
$cnv1=3.2;			# now it is a variable.  Could easily be a cmd line 
				# parameter too.  We have the flexibility.
$height  =int($height/$cnv1);	# divide feet by 3.2 to get metres

&howfar;
print "With a glide ratio of $ratio:1 you can fly $distance from $height\n";

$ratio++;
&howfar;
print "With a glide ratio of $ratio:1 you can fly $distance from $height\n";

$ratio-=2;
&howfar;
print "With a glide ratio of $ratio:1 you can fly $distance from $height\n";

sub howfar {
	$distance=int($height*$ratio);
}

We could of course build the print statement into the subroutine, but I usually separate output presentation from the calculation. Again, that means it is easier to modify later on.

Something else we can improve about this code is the use of the $ratio variable. We are having to keep track of what we do to it -- first add one, then subtract two in order to subtract one from the original input. In this case it is fairly easy, but with a complex program it can be difficult, and you don't want to be creating lots of variables just to track one input, for example $ratio1 , $ratio2 etc.