Perl初心者の部屋
PageID:Perl 425traps J

Perl4 から Perl5への罠 和訳

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


例 1 - perltrapより

@ はダブルクォートされた文字列の中で常に配列を展開するようになりました。

print "To: someone@somewhere.com\n";
perl4 出力:
To:someone@somewhere.com
perl5 エラー :
リテラルの @somewhere は今はバックスラッシュが必要です


例 2 - perltrapより

Perlには文字列のようにみえていた裸の単語(Barewords)は、 コンパイラがその裸の単語を見た個所よりも前に それと同じ名前のサブルーチンが定義されていた場合には、 サブルーチンコールと解釈されるようになりました。 たとえば:

sub SeeYa { warn"Hasta la vista, baby!" } $SIG{'TERM'} = SeeYa; print "SIGTERM is now $SIG{'TERM'}\n";
perl4 出力:
SIGTERM is main'SeeYa
perl5 出力:
SIGTERM is now main::1
これを捕捉するには -w を使用します


例 3 - perltrapより

"_"(アンダスコア) で始まるシンボルはもはやパッケージ mainに 強制的に組み入れらることはありません。 例外は、$_ 自身 (および @_ 他)。

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


例 4 - perltrapより

ダブルコロンは今は識別子の中での有効なパッケージセパレータです。 パッケージが存在しない場合、 以下のようにperl4 対 perl5では異なった振る舞いをします。

$a=1;$b=2;$c=3;$var=4; print "$a::$b::$c "; print "$var::abc::xyz\n";
perl4 出力:
1::2::3 4::abc::xyz
perl5 出力:
3
関連したノートとして、Paul Marquess が報告: 今は::が好ましいパッケージデリミタであるとすれば、 これがバグとして切り分けされるべきかどうか議論の余地があります。 (旧式のパッケージデリミタ, ' ,がここで使用される) $x = 10 ; print "x=${'x}\n" ;
perl4 出力:
x=10
perl5 出力:
Can't find string terminator "'" anywhere before EOF


例 5 - perltrapより

s'$lhs'$rhs' は現在ではどちらの側も展開されません。 従来$rhsは展開していませんでしたが、$lhsは 展開していました。 (なお文字列中のリテラル$にはマッチしません)

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


例 6 - perltrapより

splice() の 2 番目と3番目の引数は(本にある通り) リストコンテキストよりむしろ、スカラコンテキストで評価されるようになりました。

sub sub1{return(0,2) } # 2-要素の配列を戻す sub sub2{ return(1,2,3)} # 3-要素の配列を戻す @a1 = ("a","b","c","d","e"); @a2 = splice(@a1,&sub1,&sub2); print join(' ',@a2),"\n";
perl4 出力:
a b
perl5 出力:
c d e


例 7 - perltrapより

優先順位によって意味エラーが起こります。

@list = (1,2,3,4,5); %map = ("a",1,"b",2,"c",3,"d",4); $n = shift @list + 2; # リストの最初の項目に2をプラス print "n is $n, "; $m = keys %map + 2; # ハッシュ中の項目数[訳注:a-dまでで4]に2をプラス print "m is $m\n";
perl4 出力:
n is 3, m is 6
perl5 エラーとなりコンパイルに失敗


例 8 - perltrapより

代入演算子(assignment operator)の優先順位は代入の優先順位と同じに なりました。 Perl 4では誤って結合(associated)演算子の優先順位を それらに与えていました。 ですから、今度は下記のように表現の中でそれらを丸括弧で括らなければなりません。

/foo/ ? ($a += 2) : ($a -= 2); こうしないと、 /foo/ ? $a += 2 : $a -= 2; は下記のように間違って構文解析されてしまいます。 (/foo/ ? $a += 2 : $a) -= 2; 一方、 $a += /foo/ ? 1 : 2; は、今はCプログラマが期待しているように動きます。


例 9 - perltrapより

open FOO || die; は、もはや正しくありません。ファイルハンドルの前後に丸括弧が必要です。 そうしないと、perl5 は、それがデフォルトの優先順位ですというような ステートメントを残します。 open(FOO || die);perl4 openし、できなければdie
perl5 エラー:
Precedence problem: open FOO should be open(FOO) (優先順位の問題: open FOOは open(FOO)としなければなりません)


例 10 - perltrapより

フォーマット文の引数リストの要素はリストコンテキストで評価されるように なりました。このことにより、リスト値を展開できるようになりました。

@fmt = ("foo","bar","baz"); format STDOUT= @<<<<< @||||| @>>>>> @fmt; . write;
perl4 エラー:
Please use commas to separate fields in file (ファイルの中で各フィールドを分けるにはコンマを使って下さい)
perl5 出力:
foo bar baz


例 11 - perltrapより

最適化によってなくなるブロック内に goto することはできません。 ちぇっ。

goto marker1; for(1){ marker1: print "Here I is!\n"; }
perl4 出力:
Here I is!
perl5 coreファイルをダンプ (SEGV)


例 12 - perltrapより

空白を変数名やクォート構文の区切り文字に使うことは、 もはや構文的に正しくなくなりました。ちぇっ、ちぇっ。

$a = ("foo bar"); $b = q baz ; print "a is $a, b is $b\n";
perl4 出力:
a is foo bar, b is baz
perl5 エラー:
Bare word found where operator expected (演算子があるはずの所に裸の単語が見つかりました)


例 13 - perltrapより

関数 caller() は呼び元がないとき、 スカラコンテキストで偽を返すようになりました。これにより、 ライブラリファイルは、自分が require されているかどうかを判断します。

caller() ? (print "You rang?\n") : (print "Got a 0\n");
perl4 エラー:
There is no caller (呼び元がありません)
perl5 出力:
Got a 0


例 14 - perltrapより (Tchristからの支援を得て)

m//g は状態を正規表現の方にではなく、検索文字列の方に括りつけます。 (一旦ブロックのスコープがサブルーチンに移ってしまうと、 検索文字列の状態は失われます)

$_ = "ababab"; while(m/ab/g){ &doit("blah"); } sub doit{local($_) = shift; print "Got $_ "}
perl4 出力:
blah blah blah
perl5 出力:
infinite loop blah...(blah...の無限ループ)
[訳注:出力はblahではなくGot blahとなります。]


例 15 - perltrapより

reverse()はsortのサブルーチン名としては、認められなくなりました。

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


例 16 - perltrapより

ダブルクォート文字列が、エスケープされていない $ や@で 終了することがなくなりました。

$foo = "foo$"; $bar = "bar@"; print "foo is $foo, bar is $bar\n";
perl4 出力:
foo is foo$, bar is bar@
perl5 エラー:
Final $ should be \$ or $name(最後の$は\$あるいは$名前であるべきです)

注意:perl5は$barにあるおしまいの@ではエラーに なりません。perltrapではバグとして報告されてきました。


例 17 - perltrapより (Chaim Frenkelからの支援を得て)

古い while/if BLOCK BLOCK の構文は、もはやサポートされていません

if { 1 } { print "True!"; } else { print "False!"; }
perl4 出力:
True!
perl5 エラー:
syntax error at test.pl line 1, near "if {"


例 18 - perltrapより

配列に負の添え字を与えると、配列の終わりから数えるようになりました。

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


例 19 - perltrapより, Chaim Frenkelによる事例

コンマ演算子をスカラコンテキストで使うと、その引数にもスカラコンテキストが 適用されることを保証するようになりました。

@y= ('a','b','c'); $x = (1, 2, @y); print "x = $x\n"; # Perl4 出力: x = c # リストコンテキストはリストを展開すると考える # Perl5 出力: x = 3 # スカラはリストの長さを使うと知っている


例 20 - perltrapより

** 演算子は、単項のマイナスよりも強く結合するようになりました。 このように動作すると以前からドキュメントに書かれていましたが、 そうはなっていませんでした。

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


例 21 - perltrapより (Chaimからの支援を得て)

$#arrayを小さく設定すると、それ以降の配列の要素は捨てられ、 その回復は不可能となりました。

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


例 22 - perltrapより

"this is $$x" という構文はその時点でのpid を展開したものでしたが、 今では$x.をdereferenceしようとします。 しかしながら、$$自体はちゃんと機能します。

print "this is $$x\n";
perl4 出力:
this is XXXx (XXX is the current pid)(XXXは現在のpidです)
perl5 出力:
this is


例 23 - perltrapより

配列ではないリストを反復照査している(iterating)時のforeachの意味が ほんのわずかですが変わりました。 かつては一時的な配列にそのリストを割り当てていましたが、 (効率性をよくするため)もはやそうはしないのです。つまり、 値のコピーではなく実際の値を反復照査するようになったわけです。 ループ変数に対する変更は元の値を変えることになります。

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

Perl 4の解釈を維持するには、リストを陽に一時的な配列に代入してから、 それを反復照査する必要があります。例えば、下記の

foreach $var (grep(/ab/,@list)){ は、次のように変える必要があるでしょう。 foreach $var (@tmp = grep(/ab/,@list)){ そうしないと、$varを変えることで@listの値を 上書きしてしまうことになります。 (これがよく起きるのはたいてい、ループ変数に$_を使い、 $_にちゃんとlocalを適用しないままループ中で サブルーチンをコールした時です。)


例 24 - Adobe folksによる提出

eval "EXPR"を使ってあっというまに(on the fly)ハッシュを生成するには、 ハッシュ名を明確にするために$は2つ共エスケープするか、または 両側の中括弧をエスケープすることが要求されるようになりました。

両側の中括弧がエスケープされれば、結果はperl4 と perl5で コンパチブルになるでしょう。 これは非常に共通した習慣(common practice)であり、 できるだけeval{}のようなブロック形式を使うよう変更すべきです。

$hashname = "foobar"; $key = "baz"; $value = 1234; eval "\$$hashname{'$key'} = q|$value|"; (defined($foobar{'baz'})) ? (print "Yup") : (print "Nope");
perl4 出力:
Yup
perl5 出力:
Nope
eval "\$$hashname{'$key'} = q|$value|"; eval "\$\$hashname{'$key'} = q|$value|"; に変更すると次のような結果を生じます。:
perl4 出力:
Nope
perl5 出力:
Yup
あるいは、 eval "\$$hashname\{'$key'\} = q|$value|"; に変更すると次のような結果を生じます。:
perl4 出力:
Yup
perl5 出力:
Yup
両方のバージョンでコンパチブルになります。


例 25 - Adobe folksによる提出

変数から変数へのグロブ代入は、 代入された変数が代入に続いて局所化された場合は失敗します。

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


例 26 - Johan Vromansによる提出

マッチで丸括弧が使われない場合、Perl4 ではちょうど$&のように マッチ部分が$+に設定されます。 Perl5 では設定されません。 I

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


例 27 - Stephen Bealによる提出

論理テストがfalse(0)に対する評価を行う場合、 そのテストからの戻り値の代入はPerl 5ではうまく働きません。 論理テストは 0の代わりに空文字列を戻すようになったのです。

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


例 28 - Johan Vromansによる提出 (Linux 1.3.45)

Danny Faughtからの事例

現存する dbmデータベースで、perl 4の下(または他のdbm/ndbmツール)で 生成されたものは、perl 5の下で走らせると同じスクリプトでも 失敗に終わるかもしれません。 perl 5のビルドは、dbmopen()が正しく機能するには、デフォルトでdbm/ndbmと リンクされていなければなりません。

dbmopen (%dbm, "file", undef); print "ok\n";
perl4 出力:
ok
perl5 出力:
ok (IFF linked with -ldbm or -lndbm)
perl5.002と共にこのことで利益を得る人はおそろしく大勢います。 linuxとおそらくNTPerl関係がそうだと思われますが、問題点を真に 理解するにはもっと多くの報告を私は必要としています。- Bill


例 29 - Chaim Frenkelによる提出

(文字列の)単項否定における変更
この変更は戻り値と、自動(マジック)インクリメントに対して行うもの両方に 影響を与えます。

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


例 30 - Simon Chatterjeeによる提出

s`lhs`rhs`はバッククォート拡張がなくても正しく置換されるように なりました。

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


例 31 - Simon Chatterjeeによる提出

フォーマットされた出力と有意の桁(significant digits)

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


例 32 - Danny Faughtによる提出

perl 4は定数を変更してしまいます:

$foo = "x"; &mod($foo); for ($x = 0; $x < 3; $x++) { &mod("a"); } sub mod { print "before: $_[0]"; $_[0] = "m"; print " after: $_[0]\n"; }
perl4 出力:
before: x after: m before: a after: m before: m after: m before: m after: m
perl5 出力:
before: x after: m Modification of a read-only value attempted at foo.pl line 12.   (fool.plの12行で読み専用の値に変更) before: a


例 33 - Danny Faughtによる提出

ちょっとした覚え書きです。 Perl 5では@_の局所化はいつも破られてきました。(特にdefgvが他のguisesと 関連しているところ)。 私の5.001mコレクションからこれを試してみて下さい。 (これを報告するのに時間はかからなかったと思います。:-( )

for (1..10) { print "Trial $_\n"; &foo('a', 'b', 'c') } sub foo { local(@_) = ('p', 'q', 'r'); } この問題は5.003で対処されるでしょう。 - Bill


例 34 - Maurice Cinquiniによってc.l.p.miscに書き留められた

以前のperlのバージョンにあるバグを知らず知らずあてにした 古いperl4 プログラムに出くわしました。

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


例 35 - Markus F.X.J. Oberhumer and Danny Faughtによる提出

正規表現で使用される変数がより厳しく解析

s/^([^$grpc]*$grpc[$opt$plus$rep]?)//o;
perl4:
compiles w/o error
perl5:
with scaler found where operator expected ..., near "$opt$plus"
見かけ上は同じスクリプトですが、以下の例で加えられるコンポーネントは、 置換の後のs'd文字列の実際の値です。例− 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 出力:
bar
perl5 出力:
barfoo)? [訳注:Perl for Win32(5.001mベース)では出力はbarとなりました。]


例 36 - Kenneth Albanowski from Eric Hendricksonによる提出

Perl 4のもとでは、/x/ あるいは m!x!のように 繰り返しマッチしていましたが、Perl 5では、m?x?は ?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 出力:
perl4
perl5 出力:
perl5


例 37 - Jerry Whelanによる提出

構文解析;. と =の間のスペースに注目

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


例 38 - Danny Faughtによる提出

ふるまいがわずかですが異なっています:

print "$x", defined $x
perl4:
1
perl5:
&lt;no output, $x is not called into existence&gt; (出力なし、$xは生じていません)


例 39 - Danny Faughtによる提出

また、配列参照についても注意を払わなければなりません。: これは例24に関連しているかもしれません。

print "$foo{"
perl4 出力:
{
perl5 出力:
syntax error


例 40 - Danny Faughtによる提出

同様に、下記に警戒して下さい。:

$foo = "array"; print "\$$foo{bar}\n";
perl4 出力:
$array{bar}
perl5 出力:
$
Perl 5は存在しない$array{bar}を探していますが、 perl 4は単に自動的に$fooを"array"に拡張することで 喜んでいます。 evalの中では特にこのことに警戒して下さい。


例 41 - Danny Faughtによる提出

これは#4に関連していますが、本当は優先順位に関連しているのです。:

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


例 42 - Danny Faughtによる提出

Perl 5でのよりよい構文解析

sub foo {} &foo print("hello, world\n"); fooは引数を一つも取らないので、-wスイッチを付けたperl 4では、うっかり セミコロンを付け忘れても動くと思われます。

しかし、perl5 こう言います:

syntax error at sub.pl line 3, near "print" Execution of sub.pl aborted due to compilation errors. (sub.plの3行目、"print"近くで文法エラー  コンパイルエラーによりsub.plの実行はお流れになりました。)


例 43 - Danny Faughtによる提出 (From Earl Hood)

変数の自殺

$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"; # 何が出力されるべきか $GlobalLevel++; if( $GlobalLevel<4 ) { &test( *aNewLocal ); } } DOS及びOSF1の元でのPerl4.019から4.036までのインタープリタのSTDOUT(標準出力): MAIN:global value SUB: global value SUB: level 0 SUB: level 1 SUB: level 2 DOS, win95, Linux, OSF1の元での4つの様々なPerl 5.xxインタープリタの STDOUT(標準出力): MAIN:global value SUB: global value SUB: this should never appear SUB: this should never appear SUB: this should never appear 変数の自殺のふるまいはPerl 5の元ではより一貫しています。 理由は、スカラが使われた場合は、Perl 4 も 5も 連想配列に対するPerl 5のようなふるまいを示すからです。


例 44 - Adobe folksによる提出 (SysV 特有)

Under SysV 系OSのもとでも、 ">>"の追加モードでオープンされたファイルで使われるseek()は、fopen()manページに ある通り正しく機能するようになりました。 例えば、追加用にファイルがオープンされる時、既にファイル内にある情報を 上書きすることは不可能です。

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


例 45 - Lionel Consによる提出 (HPUX特有)

HPUXの元では、シグナルハンドラはみんな リセットしなければなりませんでしたが、Perl4 は、シグナルハンドラ関数内では、 その度一つのシグナルが処理されるだけでした。 Perl5 ではリセットは正しく行われるようになりました。 リセットされないハンドラをあてにするコードはみんな 改訂しなければならなくなるでしょう。

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) 出力:
Got INT...
perl5 (HPUX) 出力:
Got INT... Got INT...


ご意見、ご要望、ご質問は、 電子メールまたは 質問にお願い致します。
Perl初心者の部屋へ戻る。