Scalars and Boolean and String Operators

In this third part of a five-part series on scalars in Perl, we continue our study of operators, moving on to Boolean and string operators. This article is excerpted from chapter two of the book Beginning Perl, written by James Lee (Apress; ISBN: 159059391X).

The NOT Operator

Finally, you can flip the number completely, and replace all the 1s by 0s and vice versa. This is done with the not, or ~, operator:

85   01010101
170   10101010

Let’s see, however, what happens when we try this in Perl:

#!/usr/bin/perl -w
# bitop2.pl

print "NOT 85 is ", ~85, "n";

Depending on the computer, the answer might be

$ perl bitop2.pl
NOT 85 is 4294967210
$

Your answer might be different, and we’ll explain why in a second.

Why is it so big? Well, let’s look at that number in binary to see if we can find a clue as to what’s going on:

4294697210  11111111111111111111111110101010

Aha! The last part is right, but it’s a lot wider than we’re used to. That’s because the previous examples only used 8 bits across, whereas many computers store integers as 32 bits across, so what’s actually happened is this:

85          00000000000000000000000001010101
4294697210  11111111111111111111111110101010

If you get a much bigger number, it’s because your computer represents numbers internally with 64 bits instead of 32, and Perl has been configured to take advantage of this.

Truth and Falsehood

True and false are important in Perl. In Perl, false is defined as

  1. 0
  2. “0” 
     
  3. “” (also known as the empty string
     
  4. Undefined 
     
  5. Empty list (we’ll discuss this in Chapter 4)

Later, we will want to perform actions based on whether something is true or false, like if one number is bigger than another, or unless a problem has occurred, or while there is data left to examine. We will use comparison operators to evaluate whether these things are true or false so that we can make decisions based on them.

Some programming languages represent false as 0 and true as 1, and this allows us to use operators very similar to those bitwise operators we’ve just met to combine our comparisons, and to say “if this or this is true,” “if this is not true,” and so on. The idea of combining values that represent truth and falsehood is called Boolean logic, after George Boole, who invented the concept in 1847, and we call the operators that do the combining Boolean operators.

{mospagebreak title=Comparing Numbers for Equality}

The first simple comparison operator is ==. Two equals signs tells Perl to “return true if the two numeric arguments are equal.” If they’re not equal, return false. Boolean values of truth and falsehood aren’t very exciting to look at, but let’s see them anyway:

#!/usr/bin/perl -w
# bool1.pl

print "Is two equal to four? ",          2 == 4, "n";
print "OK, then, is six equal to six? ", 6 == 6, "n";

This will produce

$ perl bool1.pl
Is two equal to four?
OK, then, is six equal to six? 1
$

This output shows that in Perl, operators that evaluate to false evaluate to the empty string ( "" ) and when true evaluate to 1.

The obvious counterpart to testing whether things are equal is testing whether they’re not equal, and the way we do this is with the != operator. Note that there’s only one = this time; we’ll find out later why there had to be two before.

#!/usr/bin/perl -w
# bool2.pl

print "So, two isn’t equal to four? ", 2 != 4, "n";

$ perl bool2.pl
So, two isn’t equal to four? 1
$

There you have it, irrefutable proof that two is not four. Good.

Comparing Numbers for Inequality

So much for equality, let’s check if one thing is bigger than another. Just like in mathematics, we use the greater-than and less-than signs to do this: < and > .

#!/usr/bin/perl -w
# bool3.pl

print "Five is more than six? ",      5 > 6, "n";
print "Seven is less than sixteen? ", 7 < 16, "n";
print "Two is equal to two? ",        2 == 2, "n";
print "One is more than one? ",       1 > 1, "n";
print "Six is not equal to seven? ",  6 != 7, "n";

The results should hopefully not be very new to you:

$ perl bool3.pl
Five is more than six?
Seven is less than sixteen? 1
Two is equal to two? 1
One is more than one?
Six is not equal to seven? 1
$

Let’s have a look at one last pair of comparisons: we can check greater-than-or-equal-to and less-than-or-equal-to with the >= and <= operators respectively.

#!/usr/bin/perl -w
# bool4.pl

print "Seven is less than or equal to sixteen? ", 7 <= 16, "n";
print "Two is more than or equal to two? ", 2 >= 2, "n";

As expected, Perl faithfully prints out

$ perl bool4.pl
Seven is less than or equal to sixteen? 1 Two is more than or equal to two? 1
$

There’s also a special operator that isn’t really a Boolean comparison because it doesn’t give us a true-or-false value; instead it returns 0 if the two are equal, –1 if the right-hand side is bigger, and 1 if the left-hand side is bigger—it is denoted by <=> .

#!/usr/bin/perl -w
# bool5.pl

print "Compare six and nine? ",    6 <=> 9, "n";
print "Compare seven and seven? ", 7 <=> 7, "n";
print "Compare eight and four? ",  8 <=> 4, "n";

gives us

$ perl bool5.pl
Compare six and nine? -1
Compare seven and seven? 0
Compare eight and four? 1
$

The <=> operator is also known as the spaceship operator or the shuttle operator due to its shape.

We’ll see this operator used when we look at sorting things, where we have to know whether something goes before, after, or in the same place as something else.

{mospagebreak title=Boolean Operators}

As well as being able to evaluate the truth and falsehood of some statements, we can also combine such statements. For example, we may want to do something if one number is bigger than another and another two numbers are the same. The combining is done in a very similar manner to the bitwise operators we saw earlier. We can ask if one value and another value are both true, or if one value or another value are true, and so on.

The operators even resemble the bitwise operators. To ask if both truth values are true, we would use && instead of & .

So, to test whether 6 is more than 3 and 12 is more than 4, we can write

6 > 3 && 12 > 4

To test if 9 is more than 7 or 8 is less than 6, we use the doubled form of the | operator, || :

9 > 7 || 6 > 8

To negate the sense of a test, however, use the slightly different operator ! ; this has a higher precedence than the comparison operators, so use parentheses. For example, this tests whether 2 is not more than 3:

!(2>3)

while this one tests whether !2 is more than 3:

!2>3

2 is a true value. !2 is therefore a false value, which gets converted to 0 when we do a numeric comparison. We’re actually testing if 0 is more than 3, which has the opposite effect to what we wanted.

Instead of those forms, && , || , and ! , we can also use the slightly easier-to-read versions, and , or , and not . There’s also xor , for exclusive or (one or the other but not both are true), which doesn’t have a symbolic form. However, you need to be careful about precedence again:

#!/usr/bin/perl -w
# bool6.pl

print "Test one: ", 6 > 3 && 3 > 4, "n"; print "Test two: ", 6 > 3 and 3 > 4, "n";

This prints, somewhat surprisingly, the following:

$ perl bool6.pl
Useless use of a constant in void context at bool6.pl line 5.
Test one:
Test two: 1$

We can tell from the presence of the warning about line 5 and from the position of the prompt that something is amiss (or least Unix users can—Windows users need to be a bit more alert since Windows automatically adds a newline character at the end of the program so the system prompt will be on the next line, but the blank line that is expected will not be there). Notice the second newline did not get printed. The trouble is, and has a lower prece dence than && . What has actually happened is this:

print("Test two: ", 6 > 3) and (3 > 4, "n");

Now, 6 is more than 3, so that returned 1, print() then returned 1, and the rest was irrelevant.

{mospagebreak title=String Operators}

After that lot, there are surprisingly few string operators. Actually, for the moment, we’re only going to look at two.

The first one is the concatenation operator, which glues two strings together into one. Instead of saying

print "Print ", "several ", "strings ", "here", "n";

we could say

print "Print " . "one ". "string " . "here" . "n";

As it happens, printing several strings is slightly more efficient, but there will be times you really do need to combine strings together, especially if you’re putting them into variables.

What happens if we try and join a number to a string? The number is evaluated and then converted:

#!/usr/bin/perl -w
# string1.pl

print "Four sevens are ". 4*7 ."n";

which tells us, reassuringly, that

$ perl string1.pl
Four sevens are 28
$

The other string operator is the repetition operator, marked with an x . This repeats a string a given number of times:

#!/usr/bin/perl -w
# string2.pl

print "GO! " x 3, "n";

will print

$ perl string2.pl
GO! GO! GO!
$

We can, of course, use it in conjunction with concatenation. Its precedence is higher than the concatenation operator’s, as we can easily see for ourselves:

#!/usr/bin/perl -w
# string3.pl

print "Ba" . "na" x 4 ,"n";

On running this, we’ll get

$ perl string3.pl
Banananana
$

In this case, the repetition is done first (“nananana”) and then it is concatenated with the “Ba”. The precedence of the repetition operator is the same as the arithmetic operators, so if you’re working out how many times to repeat something, you’re going to need parentheses:

#!/usr/bin/perl -w
# string4.pl

print "Ba" . "na" x 4*3 ,"n";
print "Ba" . "na" x (4*3) ,"n";

Compare:

$ perl string4.pl
Argument "nananana" isn’t numeric in multiplication (*) at string4.pl line 4.
Ba0
Banananananananananananana
$

Why was the first one Ba0 ? The first thing was the repetition, giving us “nananana”. Then the multiplication—What’s “nananana” times three? When Perl converts a string to a number, it takes any spaces, an optional minus sign, and then as many digits as it can from the begin ning of the string, and ignores everything else. Since there were no digits here, the number value of “nananana” was 0. Also note that if the string that is converted to a number contains no numeric characters, Perl will warn you about it as shown previously.

That 0 was then multiplied by 3, to give 0. Finally, the 0 was turned back into a string to be concatenated onto the “Ba”.

Here is an example showing how strings automatically convert to numbers by adding 0 to them:

#!/usr/bin/perl -w
# str2num.pl

print "12 monkeys"    + 0,  "n";
print "Eleven to fly" + 0,  "n";
print "UB40"          + 0,  "n";
print "-20 10"        + 0,  "n";
print "0×30"          + 0,  "n";

You get a warning for each line saying that the strings aren’t “numeric in addition (+),” but what can be converted is:

$ perl str2num.pl
Argument "12 monkeys" isn’t numeric in addition (+) at str2num.pl line 4.
Argument "Eleven to fly" isn’t numeric in addition (+) at str2num.pl line 5.
Argument "UB40" isn’t numeric in addition (+) at str2num.pl line 6.
Argument "-20 10" isn’t numeric in addition (+) at str2num.pl line 7.
Argument "0×30" isn’t numeric in addition (+) at str2num.pl line 8.
12
0
0
-20
0
$

Notice how for each of these strings, when converted to numeric values, Perl complains that the string is not numeric. This happens because the string is not a simple numeric value. But also note that Perl does convert the strings to numbers (in the case of three of the strings, the value is 0).

Our first string, "12 monkeys" , did pretty well. Perl understood the 12, and stopped after that. The next one was not so brilliant—English words don’t get converted to numbers. Our third string was also a nonstarter as Perl only looks for a number at the beginning of the string. If there’s some thing there that isn’t a number, it’s evaluated as a 0. Similarly, Perl only looks for the first number in the string. Any numbers after that are discarded. Finally, Perl doesn’t convert binary, hex, or octal to decimal when it’s stringifying a number, so you have to use the hex() or oct() functions to do that. On our last effort, Perl stopped at the x , returning 0. If we had an octal number, such as 030 , that would be treated as the decimal number 30.

Therefore, conversion from strings to numbers can be summed up with these rules:

  1. A string that is purely a number is automatically converted to the number (“21.42” is converted to 21.42).
  2. Leading whitespace is ignored (“ 12” is converted to 12). 
     
  3. Trailing nonnumerics are discarded (“12perl” is converted to 12). 
     
  4. Strings that do not start with numeric values are treated as 0 (“perl12” is converted to 0).

The last three conversions listed will produce a warning message if the -w option is used.

Please check back next week for the next part of this series.

Google+ Comments

Google+ Comments