Perl4 to Perl5 Traps

$Id: 425traps,v 1.5 1996/04/02 06:12:29 bmiddlet Exp $


Example 1 - From perltrap

@ now always interpolates an array in double-quotish strings.

print "To: someone@somewhere.com\n";
perl4 prints:
To:someone@somewhere.com
perl5 errors :
Literal @somewhere now requires backslash


Example 2 - From perltrap

Barewords that used to look like strings to Perl will now look like subroutine calls if a subroutine by that name is defined before the compiler sees them. For example:

sub SeeYa { warn"Hasta la vista, baby!" } $SIG{'TERM'} = SeeYa; print "SIGTERM is now $SIG{'TERM'}\n";
perl4 prints:
SIGTERM is main'SeeYa
perl5 prints:
SIGTERM is now main::1
Use -w to catch this one


Example 3 - From perltrap

Symbols starting with "_" are no longer forced into package main, except for $_ itself (and @_, etc.).

package test; $_legacy = 1; package main; print "\$_legacy is ",$_legacy,"\n";
perl4 prints:
$_legacy is 1
perl5 prints:
$_legacy is


Example 4 - From perltrap

Double-colon is now a valid package separator in an identifier. Thus these behave differently in perl4 vs. perl5, since the packages dont exist.

$a=1;$b=2;$c=3;$var=4; print "$a::$b::$c "; print "$var::abc::xyz\n";
perl4 prints:
1::2::3 4::abc::xyz
perl5 prints:
3
On a related note, Paul Marquess reports: Given that :: is now the preferred package delimiter, it is debatable whether this should be classed as a bug or not. (The older package delimiter, ' ,is used here) $x = 10 ; print "x=${'x}\n" ;
perl4 prints:
x=10
perl5 prints:
Can't find string terminator "'" anywhere before EOF


Example 5 - From perltrap

s'$lhs'$rhs' now does no interpolation on either side. It used to interpolate $lhs but not $rhs. (Still does not match a literal $ in string)

$a=1;$b=2; $string = '1 2 $a $b'; $string =~ s'$a'$b'; print $string,"\n";
perl4 prints:
$b 2 $a $b
perl5 prints:
1 2 $a $b


Example 6 - From perltrap

The second and third arguments of splice() are now evaluated in scalar context (as the book says) rather than list context.

sub sub1{return(0,2) } # return a 2-elem array sub sub2{ return(1,2,3)} # return a 3-elem array @a1 = ("a","b","c","d","e"); @a2 = splice(@a1,&sub1,&sub2); print join(' ',@a2),"\n";
perl4 prints:
a b
perl5 prints:
c d e


Example 7 - From perltrap

These are now semantic errors because of precedence:

@list = (1,2,3,4,5); %map = ("a",1,"b",2,"c",3,"d",4); $n = shift @list + 2; # first item in list plus 2 print "n is $n, "; $m = keys %map + 2; # number of items in hash plus 2 print "m is $m\n";
perl4 prints:
n is 3, m is 6
perl5 errors and fails to compile


Example 8 - From perltrap

The precedence of assignment operators is now the same as the precedence of assignment. Perl 4 mistakenly gave them the precedence of the associated operator. So you now must parenthesize them in expressions like

/foo/ ? ($a += 2) : ($a -= 2);Otherwise /foo/ ? $a += 2 : $a -= 2;would be erroneously parsed as (/foo/ ? $a += 2 : $a) -= 2;On the other hand, $a += /foo/ ? 1 : 2;now works as a C programmer would expect.


Example 9 - From perltrap

open FOO || die;is now incorrect. You need parens around the filehandle. Otherwise, perl5 leaves the statement as it's default precedence: open(FOO || die);perl4 opens or dies
perl5 errors:
Precedence problem: open FOO should be open(FOO)


Example 10 - From perltrap

The elements of argument lists for formats are now evaluated in list context. This means you can interpolate list values now.

@fmt = ("foo","bar","baz"); format STDOUT= @<<<<< @||||| @>>>>> @fmt; . write;
perl4 errors:
Please use commas to separate fields in file
perl5 prints:
foo bar baz


Example 11 - From perltrap

You can't do a goto into a block that is optimized away. Darn.

goto marker1; for(1){ marker1: print "Here I is!\n"; }
perl4 prints:
Here I is!
perl5 dumps core (SEGV)


Example 12 - From perltrap

It is no longer syntactically legal to use whitespace as the name of a variable, or as a delimiter for any kind of quote construct. Double darn.

$a = ("foo bar"); $b = q baz ; print "a is $a, b is $b\n";
perl4 prints:
a is foo bar, b is baz
perl5 errors:
Bare word found where operator expected


Example 13 - From perltrap

The caller() function now returns a false value in a scalar context if there is no caller. This lets library files determine if they're being required.

caller() ? (print "You rang?\n") : (print "Got a 0\n");
perl4 errors:
There is no caller
perl5 prints:
Got a 0


Example 14 - From perltrap (with help from Tchrist)

m//g now attaches its state to the searched string rather than the regular expression. (Once the scope of a block is left for the sub, the state of the searched string is lost)

$_ = "ababab"; while(m/ab/g){ &doit("blah"); } sub doit{local($_) = shift; print "Got $_ "}
perl4 prints:
blah blah blah
perl5 prints:
infinite loop blah...


Example 15 - From perltrap

reverse() is no longer allowed as the name of a sort subroutine.

sub reverse{ print "yup "; $a <=> $b } print sort reverse a,b,c;
perl4 prints:
yup yup yup yup abc
perl5 prints:
abc


Example 16 - From perltrap

Double-quoted strings may no longer end with an unescaped $ or @.

$foo = "foo$"; $bar = "bar@"; print "foo is $foo, bar is $bar\n";
perl4 prints:
foo is foo$, bar is bar@
perl5 errors:
Final $ should be \$ or $name

Note: perl5 DOES NOT error on the terminating @ in $bar This has been reported as a bug in perltrap


Example 17 - From perltrap (with help from Chaim Frenkel)

The archaic while/if BLOCK BLOCK syntax is no longer supported.

if { 1 } { print "True!"; } else { print "False!"; }
perl4 prints:
True!
perl5 errors:
syntax error at test.pl line 1, near "if {"


Example 18 - From perltrap

Negative array subscripts now count from the end of the array.

@a = (1, 2, 3, 4, 5); print "The third element of the array is $a[3] also expressed as $a[-2] \n";
perl4 prints:
The third element of the array is 4 also expressed as
perl5 prints:
The third element of the array is 4 also expressed as 4


Example 19 - From perltrap, example by Chaim Frenkel

The comma operator in a scalar context is now guaranteed to give a scalar context to its arguments.

@y= ('a','b','c'); $x = (1, 2, @y); print "x = $x\n"; # Perl4 prints: x = c # Thinks list context interpolates list # Perl5 prints: x = 3 # Knows scalar uses length of list


Example 20 - From perltrap

The ** operator now binds more tightly than unary minus. It was documented to work this way before, but didn't.

print -4**2,"\n";
perl4 prints:
16
perl5 prints:
-16


Example 21 - From perltrap (with help from Chaim)

Setting $#array lower now discards array elements, and makes them impossible to recover.

@a = (a,b,c,d,e); print "Before: ",join('',@a); $#a =1; print ", After: ",join('',@a); $#a =3; print ", Recovered: ",join('',@a),"\n";
perl4 prints:
Before: abcde, After: ab, Recovered: abcd
perl5 prints:
Before: abcde, After: ab, Recovered: ab


Example 22 - From perltrap

The construct "this is $$x" used to interpolate the pid at that point, but now tries to dereference $x. $$ by itself still works fine, however.

print "this is $$x\n";
perl4 prints:
this is XXXx (XXX is the current pid)
perl5 prints:
this is


Example 23 - From perltrap

The meaning of foreach has changed slightly when it is iterating over a list which is not an array. This used to assign the list to a temporary array, but no longer does so (for efficiency). This means that you'll now be iterating over the actual values, not over copies of the values. Modifications to the loop variable can change the original values.

@list = ('ab','abc','bcd','def'); foreach $var (grep(/ab/,@list)){ $var = 1; } print (join(':',@list));
perl4 prints:
ab:abc:bcd:def
perl5 prints:
1:1:bcd:def

To retain Perl 4 semantics you need to assign your list explicitly to a temporary array and then iterate over that. For example, you might need to change

foreach $var (grep(/ab/,@list)){to foreach $var (@tmp = grep(/ab/,@list)){Otherwise changing $var will clobber the values of @list. (This most often happens when you use $_ for the loop variable, and call subroutines in the loop that don't properly localize $_.)


Example 24 - Submitted by Adobe folks

Creation of hashes on the fly with eval "EXPR" now requires either both $'s to be protected in the specification of the hash name, or both curlies to be protected. If both curlies are protected, the result will be compatible with perl4 and perl5. This is a very common practice, and should be changed to use the block form of eval{} if possible.

$hashname = "foobar"; $key = "baz"; $value = 1234; eval "\$$hashname{'$key'} = q|$value|"; (defined($foobar{'baz'})) ? (print "Yup") : (print "Nope");
perl4 prints:
Yup
perl5 prints:
Nope
Changing eval "\$$hashname{'$key'} = q|$value|";to eval "\$\$hashname{'$key'} = q|$value|";causes the following result:
perl4 prints:
Nope
perl5 prints:
Yup
or, changing to eval "\$$hashname\{'$key'\} = q|$value|";causes the following result:
perl4 prints:
Yup
perl5 prints:
Yup
and is compatible for both versions


Example 25 - Submitted by Adobe folks

glob assignment from variable to variable will fail if the assigned variable is localized subsequent to the assignment

@a = ("This is Perl 4"); *b = *a; local(@a); print @b,"\n";
perl4 prints:
This is Perl 4
perl5 prints:


Example 26 - Submitted by Johan Vromans

If no parentheses are used in a match, Perl4 sets $+ to the whole match, just like $&. Perl5 does not.

"abcdef" =~ /b.*e/; print "\$+ = $+\n";
perl4 prints:
bcde
perl4 prints:


Example 27 - Submitted by Stephen Beal

Assignment of return values from logical tests does not work in perl5 when the test evaluates to false (0). Logical tests now return an empty string, instead of 0

$p = ($test == 1); print $p,"\n";
perl4 prints:
0
perl5 prints:


Example 28 - Submitted by Johan Vromans (Linux 1.3.45)

example from Danny Faught

Existing dbm databases created under perl4 (or any other dbm/ndbm tool) may cause the same script, run under perl5, to fail. The build of perl5 must have been linked with dbm/ndbm as the default for dbmopen() to properly

dbmopen (%dbm, "file", undef); print "ok\n";
perl4 prints:
ok
perl5 prints:
ok (IFF linked with -ldbm or -lndbm)
There are an awful lot of people getting bit by this with perl5.002 It seems to be a linux thing, and possibly NTPerl, but I sure need more reports to grok out the problem - Bill


Example 29 - Submitted by Chaim Frenkel

Changes in unary negation (of strings) This change effects both the return value and what it does to auto(magic)increment.

$x = "aaa"; print ++$x," : "; print -$x," : "; print ++$x,"\n";
perl4 prints:
aab : -0 : 1
perl5 prints:
aab : -aab : aac


Example 30 - Submitted by Simon Chatterjee

s`lhs`rhs` is now a normal substitution, with no backtick expansion

$string = ""; $string =~ s`^`hostname`; print $string, "\n";
perl4 prints:
<the local hostname>
perl5 prints:
hostname


Example 31 - Submitted by Simon Chatterjee

Formatted output and significant digits

print 7.373504 - 0, "\n"; printf "%20.18f\n", 7.373504 - 0;
Perl4:
7.375039999999996141 7.37503999999999614
Perl5:
7.373504 7.37503999999999614


Example 32 - Submitted by Danny Faught

perl 4 lets you modify constants:

$foo = "x"; &mod($foo); for ($x = 0; $x < 3; $x++) { &mod("a"); } sub mod { print "before: $_[0]"; $_[0] = "m"; print " after: $_[0]\n"; }
perl4 output:
before: x after: m before: a after: m before: m after: m before: m after: m
perl5 output:
before: x after: m Modification of a read-only value attempted at foo.pl line 12. before: a


Example 33 - Submitted by Danny Faught

Just a quick note to say that localizing @_ has always been broken in perl5 (especially where defgv is involved in other guises). Try this from my 5.001m collection (I don't believe I ever took the time to report this :-()

for (1..10) { print "Trial $_\n"; &foo('a', 'b', 'c') } sub foo { local(@_) = ('p', 'q', 'r'); }This problem will be fixed in 5.003 - Bill


Example 34 - Noted in c.l.p.misc by Maurice Cinquini

I've even come across old perl4 programs which unconsciously rely on the bugs in earlier perl versions.

perl -e '$bar=q/not/; print "This is $foo{$bar} perl5"'
perl4 prints:
This is not perl5
perl4 prints:
This is perl5


Example 35 - Submitted by Markus F.X.J. Oberhumer and Danny Faught

Stricter parsing of variables used in regular expressions

s/^([^$grpc]*$grpc[$opt$plus$rep]?)//o;
perl4:
compiles w/o error
perl5:
with Scalar found where operator expected ..., near "$opt$plus"
an added component of this example, apparantly from the same script, is the actual value of the s'd string after the substitution, e.g. - $grpc = '\)'; $opt = '\?'; $plus = '\+'; $rep = '\*'; $_ = 'foo)?'; s/^([^$grpc]*${grpc}[$opt]?)/bar/; print ;
perl4 prints:
bar
perl5 prints:
barfoo)?


Example 36 - Submitted by Kenneth Albanowski from Eric Hendrickson

Under perl5, m?x? matches only once, like ?x?. Under perl4, it matched repeatedly, like /x/ or m!x!.

$test = "once"; sub match { $test =~ m?once?; } &match(); if ( &match() ) { # m?x? matches more then once print "perl4\n"; } else { # m?x? matches only once print "perl5\n"; }
perl4 prints:
perl4
perl5 prints:
perl5


Example 37 - Submitted by Jerry Whelan

parsing; note the space between . and =

$string . = "more string"; print $string;
perl4 prints:
more string
perl5 prints:
syntax error at - line 1, near ". ="


Example 38 - Submitted by Danny Faught

The behavior is slightly different for:

print "$x", defined $x
perl4:
1
perl5:
<no output, $x is not called into existence>


Example 39 - Submitted by Danny Faught

You also have to be careful about array references: This may be related to example 24

print "$foo{"
perl4 prints:
{
perl5 prints:
syntax error


Example 40 - Submitted by Danny Faught

Similarly, watch out for:

$foo = "array"; print "\$$foo{bar}\n";
perl4 prints:
$array{bar}
perl5 prints:
$
Perl 5 is looking for $array{bar} which doesn't exist, but perl 4 is happy just to expand $foo to "array" by itself. Watch out for this especially in evals.


Example 41 - Submitted by Danny Faught

This one is related to #4, but really related to precedence:

$a = "x"; print "$::a"
perl4:
-:a
perl5:
x


Example 42 - Submitted by Danny Faught

Better parsing in perl 5

sub foo {} &foo print("hello, world\n");Since foo doesn't take any arguments, this seems to work by accident with the missing semicolon under perl 4 even with -w.

But perl5 says:

syntax error at sub.pl line 3, near "print" Execution of sub.pl aborted due to compilation errors.


Example 43 - Submitted by Danny Faught (From Earl Hood)

Variable suicide

$aGlobal{ "aKey" } = "global value"; print "MAIN:", $aGlobal{"aKey"}, "\n"; $GlobalLevel = 0; &test( *aGlobal ); sub test { local( *theArgument ) = @_; local( %aNewLocal ); # perl 4 != 5.001l,m $aNewLocal{"aKey"} = "this should never appear"; # unless identical with print "SUB: ", $theArgument{"aKey"}, "\n"; $aNewLocal{"aKey"} = "level $GlobalLevel"; # what should print $GlobalLevel++; if( $GlobalLevel<4 ) { &test( *aNewLocal ); } }STDOUT from Perl 4.019 to 4.036 interpeters under DOS and OSF1: MAIN:global value SUB: global value SUB: level 0 SUB: level 1 SUB: level 2STDOUT from four various Perl 5.xx interpreters under DOS, win95, Linux, OSF1: MAIN:global value SUB: global value SUB: this should never appear SUB: this should never appear SUB: this should never appearVariable suicide behavior is more consistent under Perl 5. Reason is that if scalars are used, both Perl 4 and 5 exhibit the behavior as Perl 5 for associative arrays.


Example 44 - Submitted by Adobe folks (SysV Specific)

Under SysV OS's, seek() on a file opened to append ">>" now does the right thing w.r.t. the fopen() man page. e.g. - When a file is opened for append, it is impossible to overwrite information already in the file.

open(TEST,">>seek.test"); $start = tell TEST ; foreach(1 .. 9){ print TEST "$_ "; } $end = tell TEST ; seek(TEST,$start,0); print TEST "18 characters here";Under perl4 (solaris) seek.test has: 18 characters here Under perl5 (solaris) seek.test has: 1 2 3 4 5 6 7 8 9 18 characters here


Example 45 - Submitted by Lionel Cons (HPUX Specific)

Under HPUX, one had to reset any signal handler, within the signal handler function, each time a signal was handled with perl4. With perl5, the reset is now done correctly. Any code relying on the handler not being reset will have to be reworked.

sub gotit { print "Got @_... "; } $SIG{'INT'} = 'gotit'; $| = 1; $pid = fork; if ($pid) { kill('INT', $pid); sleep(1); kill('INT', $pid); } else { while (1) {sleep(10);} }
perl4 (HPUX) prints:
Got INT...
perl5 (HPUX) prints:
Got INT... Got INT...


Copyright 1996 Tom Christiansen.
All rights reserved.