More WTF in Perl - YAPC::EU::2010 Pisa

WTF in Perl - YAPC::EU::2010 Pisa »
Lech Baczyński

WTF mistakes
how to avoid less known Perl pitfalls
 and save lots of debugging time
What happens when you split an empty string? When you use "scalar" function on an array reference? How to avoid some common mistakes with logical operator precedence? Who else was puzzled when calling someone else's function and it ended his loop? And more...

Splitting empty string
First, what we expect this to do?

$string = "123456";
@a = split /;/, $string;
print Dumper \@a;
Result:

$VAR1 = [
          '123456'
        ];

No surprise - array with one whole string, not splitted.
But what we expect here?

$string = ""; # note - empty string
@a = split /;/, $string;
print Dumper \@a;

Do we expect?

$VAR1 = [
          ''
        ];

The real result:

$VAR1 = [];


Empty array!
Why?
Split documentation says:
By default, empty leading fields are preserved, 
and empty trailing ones are deleted. 
(If all fields are empty, they are considered to be trailing.)
all fields are empty -> they are considered to be trailing -> 
deleted ->  the result is empty array.
"Scalar" function on an array ref


Good:
scalar @{$array_ref}
Bad:
scalar $array_ref
Bad, but *will* work... not exactly as intended...

@arr = ('w','t','f');
$array_ref = \@arr;
print scalar $array_ref 

Result?
Result:

ARRAY(0x9d447b0)

or similar

Danger one:

my $array_ref = [];
if (scalar $array_ref) {
        print "It has elements\n";
        print "Number of elements: " .  scalar $array_ref;
}
else {
        print "It is empty";
};

It has elements
Number of elements: ARRAY(0x88d0c28)

Danger two:

foreach my $i (1 .. scalar $array_ref) { print "."
 }
Do you know what it will do?
Will print lots and lots of dots.

Why?
Consider:
print int scalar $array_ref;

What it will print?
Something like:
151727144

(address in memory converted to integer)
This is why the loop 
will run millions times!
Logical operator precedence danger
"Or"

|| - high priority
or - low priority
Beware of their priority!
Example:

"Open or die"
Good:
open F, "<", "input.txt" or die $!

Bad:
open F, "<", "input.txt" || die $!

Good:
open (F, "<", "input.txt") || die $!
Example 2:

We would like to get some value... or 42 if we got no value

Bad:

$var = get_something() or 42;

Why?
$var = get_something() or 42;
means:
( $var = get_something() ) or 42;
which means:
$var = get_something() 

Good:
$var = ( get_something() or 42 );
Good:

$var = get_something() || 42 ;
Warning: calling subroutine may end a loop...

Consider that:

foreach my $thing (@things) {
....
do_something_with($thing); 
....
};
do_something_with() subroutine was written by someone else.

Seems pretty clear.
But this loop may end - unexpectedly.
This happened in real, production code.
Why?
If soemone uses 'last' in his function


sub do_something_with {

# ....

last; 

# ....

}

So beware - do not trust other people subroutines ;)
And more:
Who needs brackets?
$a = 'Hello';
print ( length ( $a ) );

output: 5 - ok
But we can omit the brackets - nice!

print length $a;

output: 5 - ok

print length $a . " letters\n" ;

output: 14 


WTF??
Length was calculated of 
concatenated strings 
$a and " letters\n"
Beware - sometimes you may ignore brackets,
sometimes you may not.


That's all folks!
Presentation should soon be available at:

perl.baczynski.com
And if we have time... ;)
($sec,$min,$hour,$mday,$mon,
$year,$wday,$yday,$isdst)
 = localtime(time)
Month - 0..11
Month day -  1..31
Why?
Easy to use as index 
of month names array
$monthnames[$mon]
@monthnames = ('Jan','Feb'....
Weekday - 0 is Sunday, 1 is monday
$year 
99 is 1999
123 is 2023
WTF?
WTF?
$year += 1900;
imagine you do not know
what _exactly_ it does, 
have to guess
Monday is 1st, Saturday is 5th, Sunday is zeroth. Beware that
Sunday is not 7th, nor 1st, as most people would thought.
This solution is good for both groups of people - those that
think that Monday is first day of weeks (as it is 1st) and those
that Sunday is at the beginning of the week (as it is zeroth) ;-)
Two digits: 
$year = 
sprintf("%02d", $year % 100);
So, just beware of those traps in localtime
How to avoid mistakes?
(of course not all may be avoided)
Experience
Your mistakes
Other people mistakes
Thank you!

Loading comments...

Please log in to add your comment.

Report abuse

More presentations by Lech Baczyński