去る2025年7月2日に Perl 5.42 がリリースされた。ので例によって perldelta を一通り眺めた。
このバージョンは実験的機能である組込みのクラス構文の実装が進展した。 他にもパフォーマンスの改良、組み込み関数・演算子・C レベル API の追加、多数のバグ修正があるが劇的な変化ではなく、発見・修正された脆弱性もかなり限定的な問題なので刺さる機能がなければ急いで移行する必要はあまりないように思われる。
以下主だった新機能の抜粋。
source::encoding
プラグマ
ソースコードが特定の文字エンコーディングで記述されていることを宣言するプラグマ。サポートされているエンコーディングは
ASCII と UTF-8 のみである。 use source::encoding 'ascii'
が宣言された字句的スコープにおいて非 ASCII
文字を記述するとコンパイル時エラーが発生するようになる。use source:encoding 'utf8'
は単に use utf8
のシノニムである。
Perl 5 は 2000 年にリリースされたバージョン 5.6 から UTF-8
によるソースコード記述をサポートしているが、後方互換性のため既定では
ASCII を前提としており、utf8
プラグマを使わない限り文字列リテラルや RegExp
リテラルはバイト列として解釈されるし、識別子にも英数字および
'_'
しか使うことができない。
識別子はともかく「リテラルは既定でバイト列である」という意味論は極めて誤用しやすい。Unicode 文字列のつもりで渡した値が意図せずバイト列であったために実行時警告・エラーを得た経験は非英語圏のプログラマなら一度ならずあるだろう。
このプラグマはそのような初歩的なバグをコンパイル時に検出することで、Perl
プログラムの最も頻出するエラーの一つを実質的に解消しようとしている。
ちなみに use v5.42
すると自動で
use source::encoding 'ascii'
も有効になるので、今まさに警告を吐いているようなアプリケーションをアップグレードする際は注意が必要である。
any
/ all
演算子
実験的機能。だが我々はこれを既に知っている。
Scalar::Util
にある同名関数の組み込み演算子版である。
パッケージ区切り子としてのアポストロフィが無効化できるようになった
Acme モジュール作者にとっては重大な変更。なおこの機能は元々このバージョンで廃止予定としてアナウンスされていたものが、CPAN 資産の保全などを目的にフィーチャ・フラグでの管理に転換したものである。
Perl のパッケージ区切り子は C++ スタイルの ::
だが、実はこれは Perl 5 からの新構文で Perl 4 では '
であった: Foo'Bar'some_func
。
この構文には文字列補間が意図しない変数を参照する (e.g.,
"$who's value is ${who::s} value"
)
とか、半端なエディタの編集モードがバグるとかいう問題があるが、より英語的な
DSL として (e.g., Test::More
が提供していた
isn't
)、あるいは一発ネタのミソとして便利に濫用されてきた歴史がある。
そのため CPAN には割とこの古い区切り子を使ったモジュールが現存しており、後方互換性のために Perl 5.42 以降のフィーチャ・バンドルを指定しない限りは今後も当面残されることになった模様である。
:writer
フィールド属性
実験的な組み込みのクラス構文におけるフィールド変数 (インスタンス変数) に付与できる新たな属性。当然ながらこれも実験的機能である。
宣言したフィールド変数に対応するセッター・メソッドを生成する。デフォルトではフィールド名に
set_
接頭辞を付した PBP
スタイルであるが、属性に引数を与えると別名にも設定できる:
$x :param :writer(mutate_x) field
ただし :reader
属性で生成されるアクセサと同名にはできないので注意すること。設定するとより右側で宣言した方のメソッドに上書きされる:
class Foo {$x :reader :writer(x) = 42;
field
}
my $obj = Foo->new;
$obj->x; # Too few arguments for subroutine 'Foo::x' (got 0; expected 1)
字句的メソッド宣言
実験的な組込みのクラス構文におけるメソッドの可視性を字句的スコープに絞る宣言。当然ながらこれも実験的以下略。
つまり my sub
のメソッド版である。スコープ外からは参照できず、またクラス (パッケージ)
のシンボルテーブルに存在しないので通常の名前ベースのメソッド呼び出しを行うと解決に失敗する。
これは一般的な OO 言語でいうところのプライベート・メソッドに相当するが、単にアクセス修飾子がどうとかいう問題ではなく、一度スコープが閉じられると動的言語である Perl のリフレクション機能を駆使しても (スクリプト水準では) 参照できない、かなり強烈なカプセル化を提供する。
字句的メソッド呼び出し演算子
字句的メソッドは通常のメソッド呼び出しができないと上で述べた。ではどうやって呼ぶのかというと、メソッドへのハードリファレンスを得てそれを使う。名前解決を介さないので通常の呼び出しより高速である。
そのためのメソッド呼び出し演算子として新たに用意されたのが
->&
である:
class RollingCounter {$max :param = builtin::inf;
field $cnt :param :reader = 0;
field
my method incr() {
$cnt = 0 if ++$cnt > $max;
}
method count() {my $curr = $cnt;
$self->&incr;
$curr;
}
}
my $counter = RollingCounter->new(max => 3);
say $counter->count for 1 .. 10;
これは要するに
my $ref = \&lexical_meth; $self->$ref(...)
の略記なので、実は字句的メソッドでない通常の (i.e., パブリック)
メソッドに対しても同様に使える。
ただし実行時の名前解決を介さないということは継承・メソッドのオーバーライドによる多態性を放棄することになる点は注意が必要である。
コメント
コメントを投稿