Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

Perlの最新動向 2021

こんにちは、エンジニアの id:mp0liiu です。

8月28日(土)の Learn Languages 2021 というイベントの Language Update というセッションで@charsbarさんと一緒に2018年以降のPerl5やPerlコミュニティの最新動向について話してきたので、そのとき話した内容に補足などしつつ記事にしていきたいと思います。

配信アーカイブはこちらから見れます。

時系列

  • 2019/5/22 Perl5.30 リリース
  • 2020/6/20 Perl5.32 リリース
  • 2020/6/24 Perl7の発表
  • 2021/5/21 Perl5.34 リリース

Perl5.30 の変更点

正規表現や文字周りの細かい改善などはありますが、正直めぼしい変更点が見られないです。

Perl5.32 の変更点

isa 演算子の実装

値があるクラスのインスタンスもしくはそのサブクラスのインスタンスかを調べる演算子です。

use feature qw( isa );

package A { use Moo }
my $obj = A->new;
  
print '$obj is instance of A.' if $obj isa A;

今まででも isa メソッドで判定できましたが、メソッドの場合クラス名からでも呼び出せてしまうので、インスタンスの場合のみ判定したい場合は長い条件や経験者でないとわからないような workaround を書く必要がありました。
これを使えばその必要がなくなります。

連鎖比較機能

例えば $x < $y && $y <= $z$x < $y <= $z といったふうに、同じ値を比較する条件式を簡潔に書けるようになりました。

間接オブジェクト記法を無効化できるように

間接オブジェクト記法は method $object @args というふうにメソッドを呼び出せる記法です。
Perl は割と英語として読み下せることを重視する文化があった*1ので、昔はこのような書き方をするのが主流でした。

次のようなコードを動かしてみると無効にできるのが確認できます。

no feature 'indirect';
new Foo; # Bareword found where operator expected, near "new Foo"

無効にしていない場合、次のようなわかりにくいエラーメッセージがでます。

new Foo; # Can't locate object method "new" via package "Foo" (perhaps you forgot to load "Foo"?)

間接オブジェクト記法は関数の括弧を省略し呼び出した場合の文法と似ていて、関数がインポートされているかどうかで間接オブジェクト記法呼び出しとして解釈される関数呼び出しとして解釈されるかが変わり、わかりにくいエラーメッセージがでる場合があります。
これがよく開発者を混乱させていたので無効にできるようにしたようです。

Perl7の発表

Perl5.32 のリリースの少し後、Conference in the Cloud にて当時のPerl5のリリースマネージャー(Pumpking)であるSawyer X氏によってPerl7が発表されました。*2

Perl7の内容は、以下のようなものでした。

  • 機能的には5.32と同じ
  • デフォルトで strict, warnings などのよく使われるプラグマや最近追加された新機能をONにし、Perl5.0以前からあるPerlの文法を複雑にしている構文を無効にする
  • 目的
    • 初心者がいろんなプラグマを覚えなくてもすぐにPerlコードを書き始められるようにすること
    • 20世紀に書かれたコードの互換性を残すことを大事にしすぎない
    • Perl6がRakuに改名され名前的にも完全に別の言語となったことで、ちゃんとPerl5の後継バージョンをだしたいというモチベーションもあった

最初に書かなければならないボイラープレートがなくなるとコードが書きやすくなりますし、初心者もとっつきやすくなるのでかなり良さそうに見えますね。
少なくとも発表後、日本のPerl界隈ではかなり好反応だった印象があります。

しかし、Perl7やPerl7の発表には様々な問題がありました。

過去のPerl5で書かれたコードを書き換えないと動かなくなる

やはり一番目立つ問題として過去のPerl5で書かれたコードを書き換えないと動かなくなることがあげられます。

Perlには後方互換性を重視する文化があり、これはPerlコアにまつわるさまざまな方針を文書化した perlpolicy にも記述されています。
発表された内容のとおりにPerl7が実装されてしまうと perlpolicy に反するわけです。

他にも後方互換性がなくなることで、次のような問題が発生することが考えられます。

  • /usr/bin/perl は常にPerl5互換だとおもっていたら、OSディストリビュータの都合で任意のタイミングでPerl7に切り替わり過去の資産が壊れてしまう
  • #!/usr/bin/perl でどのバージョンのPerlで実行しているのかが明確でなくなって、7で書いていたつもりのコードを5で実行してしまいONになっていたつもりの機能が実はOFFになってしまう
  • Linuxディストリビューションのパッケージ管理が大変になってしまう

コミュニティ内で十分に議論せずに突然発表された

コミュニティ内で十分に議論せずに Pumpking が突然発表したことも問題になりました。
従来ならこのようなPerlコアの方針の重要な変更を行う場合は Perl5 Porters(Perl5開発者向けのメーリングリストに参加しているPerlの開発に興味のある人たち)に発表してから公にするものですが、これによってコミュニティの一部からはPerl7が受け入れられにくい雰囲気になってしまいました。

より正確に言うと、コミュニティ内で十分に議論せずに突然発表されたというよりは、Pumpking は perlpolicy によって定義される Perl Porter の一人に過ぎず perlpolicy を超越した立場ではないはずなのに perlpolicy に明確に反する方針を打ち出したことが問題視されました。
Pumpking = 行政機関、Perl Porters = 立法機関 と考えてもらうとわかりやすいかと思います。
要は行政を担当する人が法律そのものを変えるような行動をしてしまったというわけですが、これによってコアチームやコミュニティ内で混乱が発生してしまい、Perl5の正式なガバナンス制定が必要だという流れになりました。

Perlコミュニティのガバナンス制定

そういった流れでガバナンス制定についていろいろ話し合いが行われ、2020年12月頃ガバナンスが制定されました。
この内容は perlgov に文書化されています。

ざっくり内容を紹介すると、コアチームとPSC(Perl Steering Council)と呼ばれる運営評議会について明確に定義されるようになりました。

コアチームはPerlの継続的な開発に携わるグループです。
基本的にはコアのコミッターで、運営評議会のメンバーを選出し、コアチームのメンバーを管理する権限を持ちます。

PSCはPerl5の新しいバージョンのリリーススケジュール、プロセスの管理など最終的な決定をする人たちのことで、コアチームから選ばれた3人のメンバーから構成されます。
従来の pumpking を置き換えるものです。
すでにPSCのメンバーはいろいろ入れ替わっていますが、現在のメンバーは Paul Evans 氏, Ricardo Signes 氏, Neil Bowers 氏の3人のようです。

Perl5と7の今後

今後の方針について混乱していたPerl5と7ですが、2021/4/11 にPSCのミーティング*3が行われ、そこで以下のような方針が決まりました。

  • 以前発表された Perl7 の内容は取り下げて、従来のバージョンによる機能ガードを続けていく(use feature version の形で新機能を有効に)
  • Perl7はそのうちリリースするが、少なくとも来年リリースされることはなくて、当分はこれまでと同じように毎年安定版のリリースを続けていく
  • 十分な機能が揃ったら Perl7 と呼ぶことになるかもしれない

Perl5.34 の変更点

コミュニティのゴタゴタがあったのであまり大きな変更点はないですが、大きな変更点としては次のようなものがあげられます。

try-catch 構文

次のように try-catch で例外処理を記述できるようになりました。

use feature qw( try );

try {
  die 'hogehoge';
}
catch ($e) {
  print $e;
}

これにより今まで eval-if で書いていた例外処理をわかりやすくかけるようになります。
また、Try::Tiny などと違って ; 忘れがなくなったり、例外処理のモジュールも乱立しがちだったのでどれを使えばいいのかあまり悩まなくて良くなります。
更に自分でコードを動かしてみた限りだと Try::Tiny などの外部モジュールとコンフリクトしないので、既存のプロジェクトにも取り入れやすそうです。

8進数数値リテラルの新構文

2進数が 0b1111、 16進数が 0xFF といったように記述できていた感じで、 8進数が 0o777 というふうに記述できるようになりました。
今までは8進数を記述する場合先頭に0をつけて 0777 というふうに書いていたので、以前より8進数の記述が見やすくなったかなと思います。

barewordファイルハンドルを無効化できるように

barewordファイルハンドルとは型グロブに格納されたファイルハンドルのことです。
昔はファイルハンドルは型グロブに格納するのが一般的でしたが、今は変数に格納するのが一般的なのでそれを強制するような機能ですね。
次のようなコードを動かしてみると無効にできるのが確認できます。

no feature 'bareword_filehandles';
open FH, '<', 'tmp.txt';
my @lines = <FH>;
close FH;

擬似的な多次元配列(multidimensional)を無効化できるように

擬似的な多次元配列というのは、ハッシュの要素を

$foo{$a, $b, $c}

というふうにアクセスすると

$foo{ join($;, $a, $b, $c) }

というふうに動作することで擬似的に多次元配列をエミュレートする機能のことです。

昔のPerlでは多次元配列を使えなかったために実装された機能で、今は使うことも目にすることもないと思いますが、ハッシュスライスの構文 @foo{$a, $b, $c} と似ていて混乱を招くので無効化できるようにしたのだと思います。

次のようなコードを動かしてみると無効にできるのが確認できます。

no feature 'multidimensional';
my %foo;
$foo{qw( a b )}; #Multidimensional hash lookup is disabled

Perl5.36以降はどうなるか

Perl5.35 での変更

開発版の Perl5.35 ですでに新機能の追加や言語機能の改善が行われています。
これらはこのまま特に問題がなければ Perl5.36 にも取り込まれると思います。

defer構文の追加

Goなど他の言語などでも見られる構文と同じような感じで、スコープを抜けたときに実行される処理を defer { ... } 内に記述することができるようになります。
この構文は perl5.35.4 で追加されました。*4

真偽値の扱いの改善

条件式などから返される値や、!!0!!1 などの真偽値を変数に代入しても真偽値としての性質を保つようになりました。
これによって他の言語との相互運用やJSONのエンコードなどデータのシリアライズなどが楽になります。
この改善は perl5.35.4 で行われました。*5

RFCとして提案されているもの

Perlの変更の提案はこちらのリポジトリを見ればわかるのですが、これらのうちからいくつか取り上げます。

forループの繰り返しごとに複数の要素を参照する構文の追加

現在のfor文だと繰り返しごとにリストの先頭から1要素ずつしか参照できませんが、for my ($foo, $bar, $baz) (@array) { ... というように複数の要素を順番に参照できるようになります。

この構文が実装されるとハッシュ内の全key, valueのペアを for my ($key, $value) (%hash) { ... } で参照できるようになります。*6

Everything Slices

ハッシュや配列に含まれる値やキー/値の完全なセットを含むスライスを取得する構文を追加しようという提案です。
具体例をあげると

 %hash{*};   # %hash{ keys %hash } と同じ
 %array[*];  # %array[ 0 .. $#array ] と同じ
 
 @hash{*};   # @hash{ keys %hash } と同じ
 @array[*];  # @array[ 0 .. $#array ] と同じ

といった感じになります。
{}, [] の中はコードも書けるようで、例えば %array[ grep {; $_ > 5 } * ] といったコードも書けます。

forループの繰り返しごとに複数の要素を参照する構文の追加と一緒に追加されると便利になりそうで、組み合わせて使うと for my ($i, $v) (%array[ *]) { ... } と書くと配列のindexと要素をイテレーションすることができるようになります。

その他

既にカンファレンスでPSCのメンバーが5.36以降どうしたいかなどといったことを話しているので、いくつか取り上げます。

FOSDOM2021 での Paul Evans氏 のトーク

2021/02/06~07 の FOSDOM2021 でPSCのメンバーである Paul Evans 氏が「Perl's Amazing Time Machine」*7というタイトルでトークしており、その中で2025年には次のような機能を実装したいという話をしていました。

  • match-case構文 の追加、現状の壊れた given-when を置き換える
  • 厳密比較演算子の追加、暗黙的な型変換をせずに値を比較する演算子
  • 静的/動的に型チェックする構文の追加
  • サブルーチンのマルチディスパッチを可能に、同名でシグネチャが違うサブルーチンを書けるようにする

Paul Evans 氏はXS(perl処理系の記述に使われているCのマクロ言語)をバリバリ書ける開発者です。
5.34 の try-catch 構文や 5.32 のisa演算子もこの方が実装しています。
Perl開発の意思決定者にバリバリコード書ける人が入るのは久しぶりのことで、これによりPerlコアの開発が活発化しそうだという期待があります。

Conference in the Cloud! A Perl and Raku Conf での Ricardo Signes 氏 のトーク

2021/06/10 の Conference in the Cloud! A Perl and Raku Conf で PSCのメンバーである Ricardo Signes 氏が「What's new in Perl? 」*8というタイトルでトークしており、その中で5.36では次のようなことをしたいと話していました。

  • use version でベストなコードが書けるようにしたい
    • warnings, utf8 の有効化
    • barewordファイルハンドル, 間接オブジェクト記法などの混乱を招きやすい機能の無効化
  • 現在20近くある実験的機能の整理、experimental を外せるものは外し、Perlに追加すべきでない機能は削除する

Perlコア以外の動向

Perlコア以外にも面白い動きがあるのでいくつかとりあげます。

Corinna

Ovid氏 によるオブジェクト指向構文をPerlコアに入れようという提案です。
github に提案や実験的実装がまとめられています。
Perlコアに現状あるオブジェクト指向プログラミング関連の機能は貧弱だったり、CPANにはそれを補うようなモジュールが乱立しているので、このような動きは学習コストが下がったりコードが書きやすくなって嬉しいです。

Perlコアにオブジェクト指向構文を入れようとする挑戦は過去にも何度かありました。
有名なものでは Stevan Little 氏が Moose をPerlコアに入れようと頑張ってたりしていましたが、Moose が大きすぎるなどでうまく行きませんでした。

仕様的には Moose や Raku の影響を大きく受けています。
Moose、Moo などのOOPフレームワークモジュールとは違って keyword plugin の仕組みを使い新しい構文を追加します。
なので ; 忘れがなくなる、記述量が減る、 $self を介さず変数から直接インスタンス変数にアクセスできてインスタンス変数の宣言がなければコンパイル時エラーになるのでtypoに気づきやすい、などといったメリットがあります。

Paul evans 氏が Object::Pad という実験的実装モジュールを作っており、既にCPANにあがっています。
彼の会社では使い始めたりもしているようです。

UV2.0 のリリース

libuv のPerlインターフェースを提供する UV が Perl foundation の助成を受けて開発が進み、バージョン2.0がリリースされました。

まとめ

ここ最近はPerlコミュニティでいろいろゴタゴタがありましたが、それもようやく落ち着いてきていて今後開発が活発になっていきそうだという感じです。
これからのPerlに期待ですね!

*1:「実用 Perl プログラミング」にはPerlで詩を書く話がでてきますが、そのことを考えると当時の雰囲気が少しわかると思います

*2:https://www.perl.com/article/announcing-perl-7/

*3:https://www.nntp.perl.org/group/perl.perl5.porters/2021/04/msg259789.html

*4:https://metacpan.org/release/WOLFSAGE/perl-5.35.4/view/pod/perldelta.pod#defer-blocks

*5:https://metacpan.org/release/WOLFSAGE/perl-5.35.4/view/pod/perldelta.pod#Stable-boolean-tracking

*6:現状でも while (my ($key, $value) = each %hash) { ... } でできますが、途中でループが止まった場合などでハマりどころがあり for my $key (keys %hash) { my $value = $hash{$key}; ... というふうに書かれることが多いです

*7:https://www.youtube.com/watch?v=Kc_bP73xNyM

*8:https://www.youtube.com/watch?v=FlGpiS39NMY