本連載では第一線のPerlハッカーが回替わりで執筆していきます。今回のハッカーはcharsbarこと石垣憲一さんで、テーマは
<前回
今後実装されそうな機能
実際にPerl本体に入った機能と、プロトタイピングに使われたCPANモジュールの機能やToDoメモを比較すると、これから実装されていくであろう機能が予想できます。同様に、Paul Evans氏がSyntax::KeywordやSyntax::Operatorといった名前を冠してリリースしているほかの実験的なモジュールも、今後取り込みの対象となっていくことが予想されます。ここではその一部を紹介します。
複数のcatchブロック ──より柔軟なエラー処理
Syntax::Keyword::Tryモジュールにはバージョン0.catchブロックを持つ構文が実験的な機能として存在しています。ここではPerl 5.isa演算子を利用して、tryブロックの中で発生したエラーが既知のMyExceptionクラスのものか、それ以外のエラーなのかを判定しています。
use v5.36;
use Exception::Class 'MyException';
use Syntax::Keyword::Try qw(
try
:experimental
);
try {
do_something()
or die MyException->throw(
error => 'exception',
);
}
catch ($e isa MyException) { ... }
catch ($e) { ... }
さまざまな演算子
Perl 5.
その反省もあって、Perl本体のほうでは演算子もキーワードと同じようにプロトタイピングできるようにするしくみの実験が続いていたのですが、Perl 5.
Syntax::Operator::Equモジュール
従来のコードでは、未定義値が入るかもしれない変数を適切に比較するには次のように書く必要がありました。
if ((defined $x && defined $y && $x eq $y) ||
(!defined $x && !defined $y)) { ... }
if ((defined $x && defined $y && $x == $y) ||
(!defined $x && !defined $y)) { ... }
Syntax::Operator::Equモジュールは、従来の等価演算子の動作に加えて両方とも未定義の場合も真を返す演算子を提供します。
use v5.37;
use Syntax::Operator::Equ;
if ($x equ $y) { ... }
if ($i === $j) { ... }
Syntax::Operator::ExistsOrモジュール
Perl 5.//演算子が導入されましたが、Syntax::Operator::ExistsOrモジュールはハッシュにキーが存在していなければ右辺の値を返す\\演算子を提供します。
use v5.37;
use Syntax::Operator::ExistsOr;
my %hash = (foo => 'bar');
say $hash{baz} \\ 'quuz'; # quuz
Syntax::Operator::Dividesモジュール
Syntax::Operator::Dividesモジュールは、倍数かどうかを判定する%%演算子を提供します。
use v5.37;
use Syntax::Operator::Divides;
for (1 .. 100) {
if ($_ %% 15) { say "FizzBuzz"; }
elsif ($_ %% 5) { say "Fizz"; }
elsif ($_ %% 3) { say "Buzz"; }
else { say $_; }
}
match~case文 ──条件分岐の再実装
複数の条件分岐を1つにまとめるgivenキーワード、whenキーワードもスマートマッチ演算子とともに廃止が決まり、削除が予定されています。その代替として、Syntax::Keyword::Matchモジュールの実験成果も取り込まれていくことでしょう。match文は、従来のgiven文と異なり比較に使う演算子を明示的に指定するのが特徴です。
use v5.37;
use Syntax::Keyword::Match;
use Syntax::Operator::Equ;
match ($str : equ) {
case (undef) {
say "not defined"
}
case ("") {
say "defined but empty"
}
default {
say "non-empty"
}
}
クラスの各種機能
Perl 5.perlclassドキュメントには、優先的な実装が期待されるToDoがいくつか記載されています。
ロール ──再利用可能なメソッド群
Object::Padモジュールには、再利用可能なメソッドをまとめたロールを定義するroleキーワードが用意されています。ロールをクラスに組み込むにはclass文の:does属性を利用します。継承の順序に応じてメソッドが上書きされていく多重継承と異なり、ロールの組込み時にはメソッドの衝突が確認されるので、うっかりメソッドが上書きされることはありません。
use Object::Pad;
role Greet {
method say_hi {
say "Hi, I'm " . $self->name;
}
}
class Person :does(Greet) {
...
# method say_hi { say "Hi, I'm $name"; }
}
Object::Padモジュールの:does属性は必要に応じて複数個設定できます。1つの:does属性の中に複数個のロールを設定することはできません。
field文のアクセサ属性 ──メソッドの自動生成
Object::Padモジュールには、field文に:readerや:writer、:accessorという属性を追加することでアクセサメソッドを自動的に生成するしくみが用意されています。
use Object::Pad;
class Person {
field $name :param :reader;
field $age :param :accessor;
# method name { $name }
# method age {
# @_ ? $age = shift : $age;
# }
}
メタプログラミング
クラスの内部を覗いたりクラスの機能を拡張したりするのに必要なメタプログラミングの機能も課題に挙がっています。メタプログラミング機能は、Object::Padモジュールのバージョン0.
use v5.36;
use Object::Pad qw(:experimental);
use Object::Pad::MetaFunctions qw(metaclass);
class Author :isa(Person) :does(Greet) { ... }
my $author = Author->new(...);
my $meta = metaclass($author);
say $_->name for $meta->superclasses;
say $_->name for $meta->all_roles;
say $_->name for $meta->direct_methods;
メタプログラミング機能については、Perlの機能変更の提案を管理しているGitHubリポジトリで、正式な機能提案に向けての議論が進んでいます。このリポジトリも最近のPerlの開発体制の変化とともに導入されたもので、もとはRFCsdeferキーワードのほか、Perl 5.builtin名前空間や、Perl 5.export_キーワードなどの議論もまとめられています。
周辺ツールの対応
クラスは新しいしくみですので、Perl本体だけでなく、周辺ツールの対応も必要になります。
たとえば、class文によるオブジェクトの内部構造は従来のbless文によるオブジェクトとは異なるため、本稿執筆時点ではData::Dumperモジュールで内部を見ようとしたり、Storableモジュールで複製を作成しようとしたりすると、エラーが発生します。
また、モジュールのバージョンを抽出するツールなどもclass文には未対応のものが多いため、そのままではCPANへのアップロードなどの際に問題が発生します。この問題については次の例のように従来のpackage文と$VERSION変数を利用したバージョン指定を併記しておくことで回避できますが、いずれはツールチェイン側の対応が入るはずです。
use v5.37;
use experimental qw(class);
package Author;
our $VERSION = '0.01';
class Author 0.01 { ... }
まとめ
今回紹介した機能はいずれもまだ実験が続いているため、正式な機能に昇格するまでには時間がかかりそうですが、プロトタイピングは済んでいるため大きく変化することはないでしょう。新たにPerlのコードを書くことがあったらぜひ積極的に使ってみてください。これらの機能がそろった暁には、Perlのメジャーバージョンが
さて、次回の執筆者は宮川達彦さんで、テーマは


