You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

255 lines
16 KiB

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My Learning Website</title>
<link href="/styles/styles.css" rel="stylesheet" type="text/css">
<link href="/programming/styles/styles.css" rel="stylesheet" type="text/css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="banner">
<h1 class="courselink">Perl 5 Essential Traning</h1>
<h2 class="lecturer">LinkedIn Learning : Bill Weinman</h2>
<h2 class="episodetitle">Best Practices</h2>
</div>
<article>
<h2 class="sectiontitle">Be Consistent</h2>
<p>Consistency is perhaps more important in Perl than in other languages due to the fact that Perl can sometimes be a little bit more unforgiving. This can make it easy for hard-to-find logical errors to sneak into your code.</p>
<p>A good example of this is the semi-colon at the end of a block of code. Recall that the semi-colon is not a terminator, it is a separator and therefore is not needed at the end of the last statement in a block of code. However, it is usually best to include it. You might add some lines of code to the block later or move lines around so you might suddenly find that you have introduced errors as a result of a missing semi-colon.</p>
<p>This would likely be an easy problem to fix but it is always better to avoid these problems. As a general rule, you will spend les time avoiding errors of this kind than you would spend if you had to track them down.</p>
<h2 class=>$variables, functions and classes</h2>
<p>Again, it is a good idea to adopt a style here and be consistent with it. Some examples of this include</p>
<pre class="inset">
my $variable_name - a common convention, although one that can vary across different languages, is to have variable names in all lower-case with words separated by an underscore character where necessary.
Package BW::Class - Naming a class with the first letter in upper-case and the remaining letters in lower-case is pretty much a standard in object-oriented languages and the practice is normally followed in Perl.
my $object = BW::Class - object instances normally follow the convention of all lower case that we see with variable names.
<br>
Incidentally, a class name is usually a single word that describes the type of object (for instance, if the object holds data relevant to employees, you might call the class Employee). As such, you wouldn't normally, if ever, see an underscore character in a class name.
CONSTANT_NAME - there are all in upper-case and that is conventional across most, if not all programming languages.
sub func_name - these also follow the same conventions as variable names. One additional point is that it is generally considered good programming practice to have a function perform just a single task and the name of the function is usually a verb that describes that task.
</pre>
<h2 class="sectiontitle">Selective Use of Comments and White Space</h2>
<p>Comments, in general, serve two purposes in your code. Both of these are seen in the example shown in figure 163.</p>
<pre class="inset">
1. # BW::Better.pm
2. # Example perl module - by Bill Weinman &lt;http://bw.org/contact/&gt;
3.
4. package BW::Better;
5. use 5.28.0;
6. use warnings;
7.
8. our $VERSION = "1.0";
9.
10. # constructor - usage: my $o = BW::Better-&gt;new( number );
11. # if you omit the number, a zero will be provided.
12. sub new {
13. my $inv = shift;
14. my $class = ref($inv) || $inv;
15.
16. my $self = {};
17. bless($self, $class);
18.
19. # default to zero
20. $self-&gt;{number} = shift || 0;
21. return $self;
22. }
23.
24. # number setter/getter
25. sub number {
26. my $self = shift;
27. $self-&gt;{number} = shift if @_;
28. return $self-&gt;{number} || 0;
29. }
30.
31. # return a better number
32. sub better {
33. my $self = shift;
34. $self-&gt;_make_better;
35. return $self-&gt;{better} || 0;
36. }
37.
38. # return a string representation of the better number
39. sub string {
40. my $self = shift;
41. return "A better number is: $self-&gt;{better}";
42. }
43.
44. # version getter
45. sub version {
46. shift;
47. return $VERSION;
48. }
49.
50. # secret sauce to make a better number.
51. sub _make_better {
52. my $self = shift;
53. my $num = $self-&gt;number() || 6;
54.
55. # sanity check, default to 6
56. $num = 6 unless $num =~ /^[0-9]+$/;
57.
58. # better number is orig plus random value 1 - 11
59. $self-&gt;{better} = $num + int(rand(10)) + 1;
60. }
61.
62. 1;</pre>
<p class="caption">Figure 163 - Better.pm tidied up a little and with more comments added</p>
<p>On the first couple of lines, we have some introductory text which tells us a little bit about the program. These introductory comments don't tell us anything about the way the code is implemented, but they are intended more for informational purposes. For example, it might tell us who wrote the program and that is the first of our two purposes for comments.</p>
<p>The second purpose is to provide some information, where necessary, about how the code is implemented. It is worth remembering that code can often be self-documenting. For example, consider the following line of code</p>
<p class="inset">$my_variable = 5;</p>
<p>You would probably read that as something like $my variable is set to a value of 5. If you also add a comment such as</p>
<p class="inset"># sets the value of my variable to 5</p>
<p>this is really just stating exactly the same thing, just in English rather than in Perl code. Comments of this nature are usually pointless since anyone who understands the code in general, someone, for example, who has learned a little syntax, the code itself tells us what it is doing.</p>
<p>Comments should be added when the meaning of the code is less clear and you want to provide some information on what is going on or why a particular implementation has been used.</p>
<h2 class="sectiontitle">Use Strict and Warnings</h2>
<p>The strict and warning pragmas are hugely important in Perl. In older versions of Perl, you will often see,</p>
<pre class="inset">
1. use strict;
2. use warnings; </pre>
<p>rather than, for example</p>
<pre class="inset">
1. use 5.28.0;
2. use warnings; </pre>
<p>The reason you don't see</p>
<p class="inset">use strict;</p>
<p>in the examples here is that it is no longer optional starting from version 5.12. This means that if you have a line such as</p>
<p class="inset">1. use 5.28.0;</p>
<p>where the version number is 5.12.0 or later, strict mode is automatically enforced. The warnings mode is still optional and that is why you will still see that pragma in use.</p>
<p>The code in figure 164 helps to understand why warnings mode is important.</p>
<pre class="inset">
1. #!/usr/bin/perl
2. # warnings.pl by Bill Weinman &lt;http://bw.org/contact/&gt;
3.
4. use 5.28.0;
5. use warnings;
6.
7. my @a = qw( one two three four five );
8.
9. my $x = func();
10. say "The result is $x";
11.
12. sub func {
13. no warnings;
14. return @a[3];
15. }</pre>
<p class="caption">Figure 164 - warnings.pl</p>
<p>If we run this, we get the following output</p>
<p class="inset">The result is four</p>
<p>On line 4, we are creating an array called @a and then on line 9, we are creating a variable, $a, and assigning it the result of running func(). We then output that result on line 10.</p>
<p>The function, func, is defined on line 12 to 15 and there are two statements inside the function. The first</p>
<p class="inset">no warnings;</p>
<p>switches off the warnings pragma so, although we did insert the pragma on line 5, it is not applying inside the function.</p>
<p>The other line</p>
<p class="inset">return @a[3];</p>
<p>is returning the element at positum 3. This seems straightforward enough, but note that we are returning a non-scalar value. Although we are only returning a single element from the list, we are returning it as a list.</p>
<p>Going back to line 9</p>
<p class="inset">my $x = func();</p>
<p>we are assigning this to a scalar value, $x and there is an automatic cast here so it becomes a scalar value and this all works as expected. However, under different circumstances, this may lead to unpredictable behaviour and may, in fact, not work at all.</p>
<p>Now, let's remove the line that switches off the warnings and run the code again. The output we get now is</p>
<pre class="inset">
Scalar value @a[3] better written as $a[3] at warnings.pl line 14.
The result is four</pre>
<p>We still get our output as before, but we also have a warning to let us know that we are using the return value in a list context rather than a scalar context and it even tells us how to correct the code.</p>
<p>So, warnings can be extremely helpful and in all likelihood, there will never be a good reason for switching them off.</p>
<h2 class="sectiontitle">Use Constants</h2>
<p>You may recall that Perl doesn't really have constants, but it does have a constant pragma which does a very good approximation. The code in figure 165 is a useful demonstration of how to create constants and why we might use them.</p>
<pre class="inset">
1. #!/usr/bin/perl
2. # constants.pl by Bill Weinman &lt;http://bw.org/contact/&gt;
3.
4. use 5.28.0;
5. use warnings;
6.
7. use constant {
8. TRUE =&gt; 1,
9. FALSE =&gt; '',
10. MAX_LEN =&gt; 2048,
11. BUF_SIZE =&gt; 1024 * 1024,
12. PI =&gt; atan2(1,1) * 4,
13. };
14.
15. use constant DEBUG =&gt; TRUE;
16.
17. if ( DEBUG ) {
18. say "max length is " . MAX_LEN;
19. say "buffer size is " . BUF_SIZE;
20. say "Pi is " . PI;
21. }
22.
23. say "Hello, World!";</pre>
<p class="caption">Figure 165 - constants.pl which demonstrates both how and why to use constants</p>
<p>The first thing to note is that we have defined most of our constants in a hash-like structure between lines 7 and 13. We also have a second constant pragma which defines a constant called DEBUG. The reason we have this in its own pragma is because it actually uses one of the constants defined in the first pragma so we have to define that first before we can define DEBUG.</p>
<p>These constants represent values that don't change so by making them constants, this means that they can't be changed. So this is a little bit more secure and less error-prone.</p>
<p>If we run this, we get the output</p>
<pre class="inset">
max length is 2048
buffer size is 1048576
Pi is 3.14159265358979
Hello, World!</pre>
<p>On line 17, we are using DEBUG in a conditional statement and outputting several values if DEBUG is true. We could put any code in here that we want to execute for debugging purposes but that we don't want to execute when the code is run normally.</p>
<p>Once we have finished debugging and we are satisfied that the code works correctly, we can change line 15 to</p>
<p class="inset">use constant DEBUG =&gt; FALSE;</p>
<p>Now, when we run the code, we get the output</p>
<p class="inset">Hello, World!</p>
<p>In effect, this creates a debugging mode we can switch on or off, depending on how we code the DEBUG constant, so this can be a useful technique for debugging.</p>
<p>Another reason for using constants is that you may have a long script where a value is used in certain places. For example, you might have a variable called $vat to represent the VAT rate. You may also be using this in several different programs.</p>
<p>If we assume this has not been implemented as a constant, if the VAT rate changes, we have to find every program that uses it so that we can update it to the new rate.</p>
<p>On the other hand, if we implement the VAT rate as a constant, perhaps in some module so that any program we create that needs to access the VAT rate can import the module, when the rate changes, we just need to change the value in the module and resave it. Any program that uses the module will then have access to the new value.</p>
<p>Actually, I'm not sure if every program that imports the module would need to be rewritten.</p>
<p>To test this, I have added a constant called VAT to Better.pm</p>
<p class="inset">use constant VAT=&gt;0.20;</p>
<p>In constants.pl. I have added this line after the constant declarations</p>
<p class="inset">my $VAT = BW::Better::VAT;</p>
<p>This is creating a local variable called VAT and initialising it with the value retrieved from Better.pm. When I run this, the output is</p>
<pre class="inset">
Hello, World!
VAT rate is 0.2</pre>
<p>I then amended the value in Better.pm to</p>
<p class="inset">use constant VAT=&gt;0.10;</p>
<p>and re-ran contstants.pl which gave me the output</p>
<pre class="inset">
Hello, World!
VAT rate is 0.1</pre>
<p>So, you can see that constants.pl, when it is executed, retrieves the value of VAT from Better.pm without any modification to constants.pl being required.</p>
<p>The problem here, is that we are declaring our constants as a variable in constants.pl. A better way may be to add a constant value</p>
<p class="inset">VAT =&gt; BW::Better::VAT,</p>
<p>This was added with the first group of constants. Note that since this is a constant value, we cannot rely on string interpolation to output since it is referenced as VAT rather than $VAT, so we need to amend our output statement. I didn't make note of this above, but this had been amended to output the VAT variable so it became</p>
<p class="inset">say "VAT rate is $VAT";</p>
<p>If we declare it as a constant in constants.pl, this output statement becomes</p>
<p class="inset">say "VAT rate is ".VAT;</p>
<p>We can summarise this method of incorporating a constant value into our code as follows:</p>
<pre class="inset-overflow">
1. We create a constant in some module which our code can access.
use constant VAT=&gt;0.20;
2. We create a constant in our code and we initialise it with the value in the module. Note that we can also, as we did in the above example, include it with a group of constants. This is why I omitted the words use contant when declaring it.
use constant VAT =&gt; BW::Better::VAT
3. When we run our code, it retrieves the value of VAT from the module. If the value has changed, it will retrieve the most recent value. This means that we only need to update this value in the module if the VAT rate changes and any code that uses the constant in this way, will always be using the updated value.</pre>
</article>
<div class="btngroup">
<button class="button" onclick="window.location.href='modules.html';">
Previous Chapter - Modules
</button>
<button class="button" onclick="window.location.href='perl5essentialtraining.html'">
Course Contents
</button>
<button class="gbutton" onclick="window.location.href='/programming/programming.html'">
Programming Page
</button>
<button class="button" onclick="window.location.href='/index.html'">
Home
</button>
</div>
</body>
</html>