Robert's Perl Tutorial

http://www.sthomas.net/roberts-perl-tutorial.htm


my Variables

So there we have it. Namespaces. They work for all the other types of variable too, like arrays and hashes. This is how you can write code and not care about what other people use for variable names -- you just declare everything with my and have your own private party. Our original program about gliding can be improved now:

($height,$ratio)=@ARGV;
$cnv1=3.2;			

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

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

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

sub howfar {
	my ($height,$ratio)=@_;
	$height  =int($height/$cnv1);
	$distance=int($height*$ratio);
}

The only change is that the parameters to the subroutine, ie the contents of the array @_ , are declared with my . This means they are now only visible within that block. The block happens to also be a subroutine. Outside of the block, the original variables are still accessible. At this point I'll introduce the technical term, which is lexical scoping. That means the variable is confined to the block -- it is only visible within the block.

We still have to be concerned with what variables we use inside the subroutine. The variable $distance is created in the subroutine and used outside of it. With larger programs this will cause exactly the same problem as before -- you have to be careful that the subroutine variables you use are the same ones as outside the subroutine. For all the same reasons as before, like two different people working on the code and use of custom extensions to Perl, that can be difficult.

The obvious solution is to declare $distance with my , and thus lexically scope it. If we do this, then how do we get the result of the subroutine? Like so:

($height,$ratio)=@ARGV;
$cnv1=3.2;			

$distance=&howfar($height,$ratio);  # run this again and delete '$distance='
print "With a glide ratio of $ratio:1 you can fly $distance from $height\n";

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

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

sub howfar {
	my ($height,$ratio)=@_;
	my $distance;
	$height  =int($height/$cnv1);
	$distance=int($height*$ratio/1000); 	# output result in kilometres not metres
}

First change -- $distance is declared with my . Secondly, the result of the subroutine is assigned to a variable, which is also named $distance. However, it is a $distance in a different namespace. Remember the two gardens. You may wish to delete the $distance= from the first assignment and re-run the code. The only other change is one to change the output from meters to kilometres.

We have now achieved a sort of Black Box effect, where the subroutine is given input and creates output. We pass the subroutine two numbers, which may or may not be variables. We assign the output of the subroutine to a variable. We care not what goes on inside the subroutine, what variables it uses or what magic it performs. This is how subroutines should operate. The only exception is the variable $cnv1. This is declared in the main body of the program but also used in the subroutine. This has been done in case we need to use the variable elsewhere. In larger programs it would be a good idea to pass it to subroutines along with the other parameters too.