スキップしてメイン コンテンツに移動

去る6月に Perl 5.32.0 がリリースされたので差分を把握するために perldelta を読んだ件

要旨

Perl 5 メジャーバージョンアップの季節がやって来たのでまともな Perl プログラマの嗜みとして perldelta を読んだ。

今回は有り体に言えばルーティン的なリリースで、言語コアの拡張は他言語にも見られる構文が実験的に入ったくらいで大きな変化はない。新機能は RegExp の拡充が主である。

比較的重要と思われる変更点を抜粋する。

新機能

isa 演算子

実験的機能。Python とか Java における isinstance とか instanceof

これまでも UNIVERSAL::isa があったが、これはメソッドなのでレシーバにオブジェクトでもクラスでもない値 (i.e., 未定義値 / bless されていないリファレンス) を置くと実行時エラーが起きるのが問題だった:

package Foo {
  use Moo;
}

package Bar {
  use Moo;
  extends 'Foo';
}

package Baz {
  use Moo;
}

use feature qw/say/;

sub do_something_with_foo_or_return_undef {
  my ($foo) = @_;

  # Returns safely if the argument isn't an expected instance, in mind.
  return unless $foo->isa('Foo');
  ...;
}

# OK.
do_something_with_foo(Bar->new);

# |undef| is expected in mind, but actually error will be thrown.
do_something_with_foo(undef);

これを避けるために今までは Scalar::Util::blessed を併用したりしていたわけだが、isa 演算子は左辺が何であっても意味のある値を返すのでよりシンプルになる:

# True
+(bless +{} => 'Foo') isa Foo;

# False
undef isa Foo;

# False
+{} isa Foo;

# False
+(bless +{} => 'Baz') isa Foo;

比較演算子の連結

Python のアレ。このために比較演算子の結合性が「連結 (chained)」に変更された。

my $x = rand(10);
say 0 <= $x < 5 ? '< 5' : '>= 5';
use Math::Round qw/nearest/;

sub PI() { 4 * atan2(1, 1) }

# Rounds to the second decimal place.
sub round($) { nearest(0.01, $_[0]) }

say round sin(0) == round cos(PI / 2) == round sin(PI) != round cos(PI)
  ? 'sin(0) = cos(π / 2) = sin(π) ≠ cos(π)'
  : 'You are in wrong universe.';

連言で繋いだ場合と比べて連結された中間の式の評価回数が一回減ることに注意が必要である; A <= B < C の式 B は一回しか評価されないのに対して、A <= B and B < C の場合は高々二回評価される。

my $x = 40;
say $x if 0 <= ++$x < 42;  # 41

my $y = 40;
say $y if 0 <= ++$y and ++$y < 42;  # Doesn't print.

副作用のある式を混ぜる方がどうかしているといえばそれまでだが。

Unicode Name プロパティ参照

\p{Name=...} で Unicode 文字を名前 (e.g., “LATIN CAPITAL LETTER A”)で参照できるようになった。これまでも \N があったが、主な違いは文字列補間が効くことと、名前に対して副パターンでマッチングできる (e.g., (qr!\p{Name=/LATIN CAPITAL LETTER [A-F]/}!)) ことである。

実験的機能の正式化

Perl 5.28 で実験的機能として導入された正規表現パターンがいくつか標準で警告なしに使えるようになった。

Script Run

ドメイン名スプーフィング (ラテン文字とキリル文字など見た目に区別しづらい字形の文字を混ぜて権威あるサイトに見せかける手法) を検出するのに有用な機能。 (*script_run:...) ないし (*sr:...) で囲んだパターンが同一の Unicode Script にある文字で成り立っていない場合バックトラックする。ただし日常的に複数の Script を使う東アジアのいくつかの言語の文字は少し特別扱いされる。

ラテン文字による別名

既存の拡張正規表現に説明的な別名を付ける試み。コア言語の特殊グローバル変数に対する English.pm のような関係だがこれは新しい構文と一緒に導入されたので特に宣言なく利用可能である。

Symbolic Alias(es)
(?=...) (*pla:...) / (*positive_lookahead:...)
(?!...) (*nla:...) / (*negative_lookahead:...)
(?<=...) (*plb:...) / (*positive_lookbehind:...)
(?<!...) (*nlb:...) / (*negative_lookbehind:...)
(?>...) (*atomic:...)

非互換な変更

字句的定数関数内の変更され得る字句的スコープ変数参照の違法化

Perl は 0 引数で暗黙に値を返す関数を定数としてインライン化するが、実はこの最適化は戻り値として字句的スコープ変数を参照するクロージャにも適用される。 一度インライン化された値は実行時に変更しても反映されないので、定数と認識されたクロージャは一般的なクロージャとは異なる挙動をすることになる:

my $x = 42;
# Constant.
my $K = sub () { $x };
# Closure; Avoiding optiomization by explicit |return|.
my $L = sub () { return $x };

say $K->() + 1;  # 43
say $L->() + 1;  # 43

$x = 0;
say $K->() + 1;  # 43 (!)
say $L->() + 1;  # 1

端的に言って最適化器のバグなのだが、Perl は意図した機能かそうでないかに関らず現実に用例がある挙動は変えないのが伝統であった。公式にこの方針が転換されたのは Perl 5.14 からで、実際に廃止予定 (deprecated) 機能の廃止ロードマップ (perldeprecation) が示されたのは Perl 5.26 からである。

この機能に関しては経過措置として Perl 5.22 から警告が出ていたが予定通り廃止された。今後はこのようなサブルーチンを定義することは単に違法であり、コンパイル時に致命的エラーとなる

なお変更され得ない字句的スコープ変数についてはこれまでどおり参照して良い。ライフサイクルを通して以下のような「変更され得る」操作を受けないのが条件である:

# Error.
$x = 0;

# Error; No matter even if the branch is never reached.
$x = 0 if 0;

# Error; Subroutines can take aliases of arguments so it can be altered.
proc($x);

また字句的スコープでない変数を参照している場合や、クロージャでないサブルーチン定義の場合はそもそもインライン化されないので関係がない:

my $x = 42;
our $y = 42;

# OK; |$y| is not a lexical variable.
my $K = sub () { $y };

# OK; Global subroutines referencing variables are not inlined.
sub L() { $x }

# OK; Ditto, even if lexical subroutines.
use feature qw/lexical_subs/;
my sub M() { $x }

その他

GitHub への移行

https://github.com/Perl/perl5 が Perl 5 のプライマリなリポジトリになった。開発も GitHub の Issues / PRs を使って行われるようになった。 ただし脆弱性の報告は相変わらず非公開のバグトラッカーとメーリングリスト (cf. perldoc perlsec) にて扱われる。

コメント

このブログの人気の投稿

LIBLINEAR 2.41 で One-class SVM が使えるようになったので Perl から触ってみよう

改訂 (Sep 15, 2020): 必要のない手順を含んでいたのでサンプルコードと記述を修正しました。 CPAN に Algorithm::LibLinear 0.22 がリリースされました (しました。) 高速な線形 SVM およびロジスティック回帰による複数の機械学習アルゴリズムを実装したライブラリである LIBLINEAR への Perl バインディングです。 利用している LIBLINEAR のバージョンが LIBLINEAR 2.30 から LIBLINEAR 2.41 に上がったことで新しいソルバが追加され、One-class SVM (OC-SVM) による一値分類が利用可能になっています (しました。) OC-SVM って何 一値分類を SVM でやること。 一値分類って何 ある値が学習したクラスに含まれるか否かを決定する問題。 HBO の「シリコンバレー」に出てきた「ホットドッグ」と「ホットドッグ以外」を識別するアプリが典型。「ホットドッグ以外」の方は犬でも神でも一つの指輪でも何でも含まれるのがミソ。 二値分類の場合正反両者のデータを集める必要があるのに対して、一値分類の学習器は正例データのみしか要求しない (ものが多い。) 主な用途は外れ値検出で、もちろんホットドッグやホットドッグ様のものを検出したりもできる。 使い方 手順自体は他の二値ないし多値分類問題と同じです。つまり、 訓練パラメータを決めて 訓練データセットで訓練して テストデータセットで確度を検証して 十分良くなったらモデルを保存する といういつもの流れ。 訓練パラメータ use 5.032 ; use Algorithm::LibLinear ; my $learner = Algorithm::LibLinear ->new( epsilon => 0.01 , nu => 0.75 , solver => ' ONECLASS_SVM ' , ); solver => 'ONECLASS_SVM' が一値分類用のソルバです。LIBLINEAR の train コマンドで言うところの -s 21 。 OC-SVM の良いところは (ハイパー)...

Perl 5 to 6 - コンテキスト

2011-02-27: コメント欄で既に改訂された仕様の指摘がありました ので一部補足しました。 id:uasi に感謝します。 これはMoritz Lenz氏のWebサイト Perlgeek.de で公開されているブログ記事 "Perl 5 to 6" Lesson 06 - Contexts の日本語訳です。 原文は Creative Commons Attribution 3.0 Germany に基づいて公開されています。 本エントリには Creative Commons Attribution 3.0 Unported を適用します。 Original text: Copyright© 2008-2010 Moritz Lenz Japanese translation: Copyright© 2011 SATOH Koichi NAME "Perl 5 to 6" Lesson 06 - コンテキスト SYNOPSIS my @a = <a b c> my $x = @a; say $x[2]; # c say (~2).WHAT # Str() say +@a; # 3 if @a < 10 { say "short array"; } DESCRIPTION 次のように書いたとき、 $x = @a Perl5では $x は @a より少ない情報—— @a の要素数だけ——しか持ちません。 すべての情報を保存しておくためには明示的にリファレンスを取る必要があります: $x = \@a Perl6ではこれらは反対になります: デフォルトでは何も失うことなく、スカラ変数は配列を単に格納します。 これは一般要素コンテキスト(Perl5で scalar と呼ばれていたもの)及びより特化された数値、整数、文字列コンテキストの導入によって可能となりました。無効コンテキストとリストコンテキストは変更されていません。 特別な構文でコンテキストを強制できます。 構文 コンテキスト ~stuff 文字列 ?stuff 真理値 +stuff ...

Perl の新 class 構文を使ってみる

Perl 5 のオブジェクト指向機能は基本的には Python の影響を受けたものだが、データを名前空間 (package) に bless する機構だけで Perl 4 以来の名前空間とサブルーチンをそのままクラスとメソッドに転換し第一級のオブジェクト指向システムとした言語設計は驚嘆に価する。 実際この言語のオブジェクトシステムは動的型付言語のオブジェクト指向プログラミングに要求されるおよそあらゆる機能を暗にサポートしており、CPAN には Moose を筆頭とした屋下屋オブジェクトシステムが複数存在しているがその多くは Pure Perl ライブラリである。つまり「やろうと思えば全部手書きで実現できる」わけである。 そういうわけで Perl のオブジェクト指向プログラミングサポートは機能面では (静的型検査の不在という現代的には極めて重大な欠如を除けば) 申し分ないのだが、しかし Moose その他の存在が示しているように一つ明らかな欠点がある。記述の冗長さだ。 コンストラクタを含むあらゆるメソッドは第一引数としてレシーバを受ける単なるサブルーチンとして明示的に書く必要があるし、オブジェクトのインスタンス変数 (a.k.a. プロパティ / データメンバ) は bless されたデータに直接的ないし間接的に プログラマ定義の方法 で格納されるためアクセス手段は実装依存である。これはカプセル化の観点からは望ましい性質だが、他者の書いたクラスを継承するときに問題となる。ある日データ表現を変更した親クラスがリリースされると突然自分の書いた子クラスが実行時エラーを起こすようになるわけだ。 そうならないためにはインスタンス変数へのアクセスに (protected な) アクセサを使う必要があるのだが、そのためには親クラスが明示的にそれらを提供している必要があるし、そもそも Perl にはメソッドのアクセス修飾子というものがないので完全な制御を与えるならばオブジェクトの内部状態がすべて public になってしまう。 そのような事情もあり、特にパフォーマンスが問題にならないようなアプリケーションコードでは Moose のようなリッチな語彙を提供するオブジェクトシステムを使うことが 公式のチュートリアルでも推奨 されてきた。Perl コアのオブジェクトシステムの改良は...

(multi-)term-mode に dirtrack させる zsh の設定

TL;DR .zshrc に以下を書けば良い: # Enable dirtrack on (multi-)term-mode. if [[ " $TERM " = eterm * ]]; then chpwd() { printf '\032/%s\n' " $PWD " } fi 追記 (May 14, 2025): oh-my-zsh を使っていれば emacs プラグインが勝手にやってくれる: plugins = ( emacs ) 仔細 term-mode は Emacs 本体に付属する端末エミュレータである。基本的には Emacs 内でシェルを起動するために使うもので、古い shell-mode よりも端末に近い動きをするので便利なのだが、一つ問題がある。シェル内でディレクトリを移動しても Emacs バッファの PWD がそのままでは追従しない点だ。 こういう追従を Emacs では Directory Tracking (dirtrack) と呼んだりするが、 shell-mode や eshell ではデフォルトで提供しているのに term-mode だけそうではない。 要するにシェル内で cd してもバッファの PWD は開いた時点のもの (基本的には直前にアクティヴだったバッファの PWD を継承する) のままなので、移動したつもりで C-x C-f などをするとパスが違ってアレっとなることになる。 実は term-mode にも dirtrack 機能自体は存在しているのだが、これは シェルがディレクトリ移動を伴うコマンドを実行したときに特定のエスケープシーケンスを含んだ行を印字することで Emacs 側に通知するという仕組み になっている。 Emacs と同じく GNU プロジェクトの成果物である bash は Emacs 内での動作を検出すると自動的にこのような挙動を取るが、zsh は Emacs の事情なんか知ったことではないので手動で設定する必要がある。 まずもって「ディレクトリ移動のコマンドをフックする」必要がある訳だが、zsh の場合これは簡単で cd / pushd / popd のようなディレクトリ...

多分週刊チラシの裏 (Oct 19, 2020 - Feb 26, 2021)

週刊とは言ったが毎週刊とは言ってないという言い訳。 C++ のコンパイルを高速化する小技 ビルドシステムやツールを変更せずともコーディングだけで改善できるコンパイル時間短縮テクニック。 #include を減らす インライン化を明示的に避ける 関数オーバーロードの可視性を制限する 公開シンボルを減らす の 4 本。 歯医者で歯を治したら記憶能力を失った話 歯医者で簡単な治療を受けた日から後、記憶が 90 分しか保持できなくなった英国の軍人の話。まるで「博士の愛した数式」だが実話である。 DRPK で売られていた Sim City っぽいゲームのリバースエンジニアリング 平壌市内のアプリストア (物理) で売られていた Sim City 風ゲームがインストールに失敗してライセンス認証で止まってしまったのでなんとか動かせないものかとリバースエンジニアリングしてみた話。 日本にあっては DPRK のデジタル事情というと 3G セルラーが現役とか国内 Web サイトのリストがポスター一枚に収まるとか何故かコンピュータ将棋の古豪とかの断片的な情報が伝え聞かれる程度だが、近頃は Android タブレットでゲームなどもできるらしい。 国内のインフラ及びエコシステム事情に合わせて元々フリーミアム + アプリ内課金モデルだったものが買い切り 5,000 KPW (< 1 USD) になっているなど、我々が失った自由が我々よりも不自由な (はずだと我々が信じている) 国に残存しているのは皮肉だろうか。 typosquatting は単なる typo じゃ済まない typo を狙って人気のあるドメインやソフトウェアに類似した名前をつける手法 (typosquatting) は人を辟易させるのみならずセキュリティの脅威である。 IQT が 2017 年から 2020 年にかけて Python ライブラリの中央リポジトリである PyPI において行った調査で、メジャーなライブラリに名前を似せたマルウェアが 40 個確認されたとのこと。 その内 16 個が単純なスペルミス狙い (e.g., “urlib3” vs. “urllib3”) で、26 個は正当なパッケージと混同するような名前 (e.g., “nmap-python” vs. “pytho...