|
In this part we are going to take a look at the data structures available in Perl and how we can use them. In Perl 5 there are basically 3 data structures. Scalars, arrays and hashes. The latter is also known as dictionaries, look-up tables or associative arrays in other languages. See the full list of entries in the Perl Tutorial. Variables in Perl are always preceded with a sign called a sigil. These signs are $, @ and %. A scalar can contain an single value such as a number or a string. It can also contain a reference to another data structure that we'll address later. The name of the scalar always starts with a $ sign followed by letters, numbers and underscores. So a variable name can be $name or $long_and_descriptive_name. It can also be $LongAndDescriptiveName but the Perl community usually prefers the former. As we are always using strict we always have to first declare our variables using my. We can either assign value immediately like in this example: use strict; use warnings; use 5.010; my $name = "Foo"; say $name; or we can declare the variable first and assign only later: use strict; use warnings; use 5.010; my $name; $name = "Foo"; say $name; We prefer the former if the logic of the code allows it. If we declared a variable but have not assigned a value yet then it has a value called undef which is similar to NULL in databases but which has slightly different behavior. We can check if a variable is undef or not using the defined function:
use strict;
use warnings;
use 5.010;
my $name;
if (defined $name) {
say 'defined';
} else {
say 'NOT';
}
$name = "Foo";
if (defined $name) {
say 'defined';
} else {
say 'NOT';
}
say $name;
We can set a variable to be undef by assigning undef to it: $name = undef; The scalar variables can hold either numbers or strings. So I can write: use strict; use warnings; use 5.010; my $x = "hi"; say $x; $x = 42; say $x; and it will just work. So how is that work together with operators and operator overloading in Perl? At this basic level Perl works in the opposite way. Instead of the operands telling the operator how to behave, the operator tells the operands how they should behave. So if I have two variables that have numbers in them then the operator decides if they really behave like numbers or if they behave like strings: use strict; use warnings; use 5.010; my $z = 3; say $z; # 3 my $y = 4; say $y; # 4 say $z + $y; # 7 say $z . $y; # 34 say $z x $y; # 3333 + adds two numbers to both $y and $z act like numbers. . concatenates two strings so both $y and $z act like strings. x repeats the string on the left hand side as many times the number on the right hand side so $z acts as a string and $y act as a number The results would be the same if they were both strings: use strict; use warnings; use 5.010; my $z = "3"; say $z; # 3 my $y = "4"; say $y; # 4 say $z + $y; # 7 say $z . $y; # 34 say $z x $y; # 3333 Or if either of them was a number and the other one is a string: use strict; use warnings; use 5.010; my $z = 3; say $z; # 3 my $y = "4"; say $y; # 4 say $z + $y; # 7 say $z . $y; # 34 say $z x $y; # 3333 Perl automatically converts numbers to strings and strings to numbers based on the requirement of the operator. These we call numerical and string contexts. The above cases were easy. When converting a number to a string it is just as if you put quotes around it. When converting a string to a number there might be the simple case as we saw, when all the string consists of just digits. The same would happen if there was a decimal dot in the string such as in "3.14" but what if the string contained characters that are not part of any number? e.g "3.14 is pi" How would that behave in numerical context? Even that is simple use strict; use warnings; use 5.010; my $z = 3; say $z; # 3 my $y = "3.14 is pi"; say $y; # 3.14 is pi say $z + $y; # 6.14 say $z . $y; # 33.14 is pi say $z x $y; # 333 but might need some explanation. Perl looked at the left side of the string and tried to convert it to number. As long as it made sense, that part became the numerical value of the variable. So in numerical context (+) the string "3.14 is pi" is regarded as 3.14. In a way it is completely arbitrary but that's how it behaves so we live with that. The above code will also generate a warning on the standard error channel (STDERR): Argument "3.14 is pi" isn't numeric in addition(+) at example.pl line 10. but only if you used use warnings. So it is important to use it to get notified when something is not exactly expected. So the result of $x + $y is now clear. To be sure, perl did not convert $y to 3.14. It just used the numerical value for the addition. So the result of $z . $y is also clear. There perl is using the original string. You might wonder why $z x $y shows 333 while we had 3.14 on the right hand side but apparently perl can only repeat a string along whole numbers. In the operation perl silently rounds the number on the right hand side. Not only that but we don't even see the warning of the partial string to number conversion that we saw in the case of +. This is not because the difference in the operator. If we comment out the addition we will see the warning on this operation. The reason is that when perl generated the numerical value of the string "3.14 is pi" it also stored it in a magic pocket of the $y variable. So effectively $y now holds both a string value and a number value and will use the right one in any new operation avoiding the conversion. There are three more things I'd like to address. One is the behavior of a variable with undef in it, the other one is fatal warnings and the third one is avoiding it.
undefIf in a variable I have undef it can still be used. In numerical context it will act as 0 in string context it will act as the empty string:
use strict;
use warnings;
use 5.010;
my $z = 3;
say $z; # 3
my $y;
say $z + $y; # 3
say $z . $y; # 3
if (defined $y) {
say "defined";
} else {
say "NOT"; # NOT
}
With two warnings: Use of uninitialized value $y in addition (+) at example.pl line 9. Use of uninitialized value $y in concatenation (.) or string at example.pl line 10. As you can see the variable is still undef at the end.
Fatal warningsThe other thing is that some people prefer that the application will throw a hard exception instead of the soft warning. The could change the beginning of the script and write use warnings FATAL => "all"; that will print 3 and then throw an exception: Use of uninitialized value $y in addition (+) at example.pl line 9.
Avoiding itIf you would like to avoid the automatic conversion of strings when there is no exact conversion you could check if the string looks like a number when you receive it from the outside world. For this we are going to load the module Scalar::Util and use the subroutine looks_like_number
use strict;
use warnings FATAL => "all";
use 5.010;
use Scalar::Util qw(looks_like_number);
my $z = 3;
say $z;
my $y = "3.14";
if (looks_like_number($z) and looks_like_number($y)) {
say $z + $y;
say $z . $y;
if (defined $y) {
say "defined";
} else {
say "NOT";
}
}
operator overloadingFinally, you could actually have operator overloading in which case the operands would tell what the operators should do but let's leave that as an advanced topic.
Perl tutorial and video courseFor further articles see the Beginner Perl Maven tutorial book and video course.In the comments, please wrap your code snippets within <pre> </pre> tags and use spaces for indentation. blog comments powered by Disqus |
Follow me: