One of the trickiest aspects of learning for newcomers to programming is to know when to split out parts of their code into named blocks. Newcomers can easily see that it's a good idea - as it means that code can be tested in smaller chunks, and that code can be shared (reused) - but it's not always obvious just how the division / split should be done.
Here's a rule of thumb ...
if you find yourself repeating something, then it's probably an excellent candidate to be a named block of code. Sometimes there's a counter-comment made -
"Yes, but I have had to alter the copy so in the end the code isn't duplicated", to which I'll reply
the places you have to alter the copy are telling you which parts of the named block of code are going to be passed in as parameters, or back as return values
From today's Perl course, here is an sample application that reads a width and a height from the user, and multiplies them together to get the area of a rectangle:
use grahamslib;
$running = "Third part";
($width) = getpval("Width");
($high) = getpval("Height",20);
$area = $width * $high;
print ("The area is $area ($width x $high)\n");
print "Running is the $running part of Maz's event\n";
The code looks short and clear enough, but a lot of the work is actually performed by the
getpval sub which we have written into a separate file. This sub meets all the classic requirements of a good sub - it has a small number of logical inputs and outputs, it performs a single distinct task, and it's the sort of thing that'll be reused in many different programs.
Here's the
getval sub, in the
grahamslib module:
use strict;
sub getpval {
my ($askem,$maxval) = @_;
my $running = 1;
my $val;
do {
print "What is the $askem ... ";
chop ($val = <STDIN>);
unless ($maxval == 0 or $val < $maxval) {
print "TOOOOO Huge\n";
} else {
$running = 0; }
} while ($running) ;
($val,"Daisy the cow","Pint of ginger beer");
}
1;
There's somewhat more there than in the simple piece of code that calls the sub - and rightly more effort should be put into developing it, as it's now available for reuse in the standard library I have created. Here are some pertinent facts if you're reading the code and wondering how it works:
• The reference to "strict" is to tell Perl that all variables must be declared with
my or in some other way - the highly dangerous default of a global variable is not permitted.
• Parameters are passed in via a list called
@_, from which the first two elements are copied into local variables called $askem and $maxval ... if there is only one value in the call, $maxval will be empty.
• The user is prompted to input, using the string passed in as the first parameter as part of the description text that's printed.
• The value entered is checked, and if a maximum was given which has been exceeded, the sub flags an error and loops to have the data re-entered
• Finally, when an acceptable value has been read it's put into a list with a couple of other strings. Since that's the last action performed in the sub, it is this list which is returned to the calling code; programmers wishing for clarity may like to add the word
return in front of the list.
• The
1; at the very end of the file is there to ensure that the code, when loaded, returns a true value. Anything that's NOT within a sub is performed as an initialisation action when it's loaded, and this code MUST return a true value - it's a feature of Perl. Without the
1; you get an error message:
Dorothy:csro8 grahamellis$ perl sboo
grahamslib.pm did not return a true value at sboo line 2.
BEGIN failed--compilation aborted at sboo line 2.
Dorothy:csro8 grahamellis$
Are you wondering about that pint of ginger beer, and Daisy the cow? Those are just two strings of text I added to the return value in the sub as I was demonstrating it to show how a list can be returned. I like my demonstrations to be fun and a bit different - to raise a smile and make
learning to Program in Perl fun.
(written 2008-10-21 19:40:16)
Associated topics are indexed under
P209 - Subroutines in Perl [2550] Do not copy and paste code - there are much better ways - (2009-12-26)
[2069] Efficient calls to subs in Perl - avoid duplication, gain speed - (2009-03-07)
[1921] Romeo and Julie - (2008-12-04)
[1860] Seven new intermediate Perl examples - (2008-10-30)
[1826] Perl - Subs, Chop v Chomp, => v , - (2008-10-08)
[1784] Global - Tcl, PHP, Python - (2008-09-03)
[1782] Calling procs in Tcl and how it compares to Perl - (2008-09-02)
[1202] Returning multiple values from a function (Perl, PHP, Python) - (2007-05-24)
[1163] A better alternative to cutting and pasting code - (2007-04-26)
[969] Perl - $_ and @_ - (2006-12-07)
[775] Do not duplicate your code - (2006-06-23)
[588] Changing @INC - where Perl loads its modules - (2006-02-02)
[531] Packages in packages in Perl - (2005-12-16)
[357] Where do Perl modules load from - (2005-06-24)
[308] Call by name v call by value - (2005-05-11)
[96] Variable Scope - (2004-10-22)
Q904 - Object Orientation and General technical topics - Analysing a Programming Task [2327] Planning! - (2009-08-08)
[1853] Well structured coding in Perl - (2008-10-24)
[1607] Learning to program in Perl - (2008-04-11)
[1513] Perl, PHP or Python? No - Perl AND PHP AND Python! - (2008-01-20)
[1345] Perl and Shell coding standards / costs of an IT project - (2007-09-11)
[747] The Fag Packet Design Methodology - (2006-06-06)
Some other Articles
Three Seasonal PicturesPerl and BlackberriesPictures from a delegateDaisy the Cow and a Pint of Ginger BeerString matching in Perl with Regular Expressions30th November - Santa Trip from MelkshamLua - IAQ (Infrequently Answered Questions)Old Piles of the South WestPassing a table from Lua into C