Perl5.32の新機能
6/22にリリースされたPerlの最新安定バージョン5.32では久しぶりにいろいろ新機能が追加されてたので、perldeltaを読みつつ試してみました。
内容は7/1にあったPerl若手の会で発表したこととほぼ同じで、そこで聞いたことを追記したりしてます。
isa 演算子
左被演算子に渡した値が右被演算子のクラスのインスタンスまたはそこから派生したクラスのインスタンスなのかを調べる演算子です。
use feature 'isa'
でこの機能を有効化でき、実験的機能使用による警告は no warnings 'experimental::isa'
で抑止できます。
use v5.32; use feature 'isa'; no warnings 'experimental::isa'; package A { use Moo } my $obj = A->new; say '$obj is instance of A.' if $obj isa A; say '$obj is instance of A.' if $obj isa 'A'; my $klass = 'A'; say '$obj is instance of A.' if $obj isa $klass;
isa演算子の追加によって、トリッキーな方法や外部モジュールを利用することなく、クラスのインスタンスまたはそこから派生したクラスのインスタンスなのかを調べることが可能になります。
Perlには以前から UNIVERSAL に isa メソッドが定義されていて、すべてのクラスから呼べるこのメソッドを使うことで呼び出し元が引数に与えたクラスのインスタンスまたはそこから派生したクラスのインスタンスなのかを調べていました。
package A { use Moo } my $obj = A->new; say '$obj is instance of A.' if $obj->isa('A');
しかし isa メソッドを呼ぶ処理を書くだけではクラスのインスタンスまたはそこから派生したクラスのインスタンスなのかを調べることができないので不便なことがあります。
まず、未定義値や空文字列からメソッドを呼び出そうとすると例外が発生するので、それらの値が来るような処理では例外が発生しないように処理を書く必要がありました。
そのような処理を書くために、 UNIVERSAL::isa
を関数として呼び出したり*1、 Scalar::Util
モジュールにある blessed
関数を利用して bless されたリファレンスかをチェックしてから isa メソッドを呼び出すといったことが行われてきました。
my $obj = undef; $obj->isa('A'); # Can't call method "isa" on an undefined value $obj = ''; $obj->isa('A'); # Can't call method "isa" without a package or object reference # UNIVERSAL::isa を関数として呼び出して判定 UNIVERSAL::isa($obj); # blessed でblessされたインスタンスか調べてから判定 use Scalar::Util qw( blessed ); say '$obj is instance of A.' if blessed($obj) && $obj->isa('A');
また、 isa メソッドは文字列からも呼び出せる為クラスのインスタンスまたはそこから派生したクラスのインスタンスかどうかを調べたい場合は不都合があり、そういったときも Scalar::Util#blessed
を利用する必要がありました。
演算子の連鎖が可能に
python のように同じ優先順位の比較演算子、等価演算子であれば連鎖して書くことが可能になりました。
$x < $y && $y <= $z
は $x < $y <= $z
、$x == $y && $x == $z
は $x == $y == $z
といったふうに記述できるようになります。
注意点がいくつかあって、まず、優先順位が違う演算子を連鎖させることは不可能です。
例えば $x < $y == $z
は $x < $y
が先に評価され、評価した結果を $z
と等価か調べる挙動となります。
また、サブルーチンや式の結果は使いまわされます。
例えば $x < expensive_sub() <= $z
は my $tmp = expensive_sub(); $x < $tmp && $tmp <= $z
と同じ挙動に、$x < $tied_scalar + 12 < $y
は my $tmp = $tied_scalar + 12; $x < $tmp && $tmp <= $z
と同じ挙動になります。
なお、 tie されたスカラ変数が演算子にそのまま渡される場合は毎回 FETCH を、演算子オーバーロードされたクラスのインスタンスの変数が演算子にそのまま渡される場合は毎回演算子に対応するメソッドを呼び出します。
例えば $x < $tied_scalar < $y
を実行すると、$x < $tied_scalar && $tied_scalar < $y
というふうに動作するので $tied_scalar
と紐付いているFETCHメソッドは2回実行され、実行されるたびに返された値で条件式が実行されます。
Unicode 13.0 のサポート
Perlは Unicode のサポートが手厚くて恒例のという感じです。
サポートにより具体的にどういったことができるかは完全に把握できていないですが、Unicode文字名でUnicode文字を指定できるようになったり、正規表現でUnicode文字特性にマッチさせることができるようになっているのを確認しています。
例えば Unicode 13.0 では忍者の絵文字が追加されているので say "\N{NINJA}"
で(OSがサポートしていれば)忍者の絵文字を標準出力に出力できたり、 "\N{NINJA}" =~ /\p{Emoji}/
でUnicode文字特性にマッチさせれたりといった感じです。
正規表現の中で \p{name=...}
と書くことでUnicode文字を表現することが可能に
今まで でも\N{...}
でUnicode文字を表現できていましたが、代わりの方法として正規表現の中なら \p{name=NAME}
でUnicode文字を表現可能になりました。
\N{...}
との主な違いは実行時に変数が展開されるところです。
my $name = "NINJA"; "\N{$name}"; # Unknown charname '$name' qr/\p{name=$name}/ # \p{name=NINJA} として解釈される
他にも細かい点で違いがあって、詳しく知りたい方はドキュメントを読むといいと思います
新しいUnicode文字特性 Identifier_Status
, Identifier_Type
のサポート
これに関してはperldeltaに貼ってある unicode.org の記事が見れなかったので詳細は不明です・・・。
分かり次第追記するかもです