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

去る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) にて扱われる。

コメント

このブログの人気の投稿

BuckleScript が ReScript に改称し独自言語を導入した

Via: BuckleScript Good and Bad News - Psellos OCaml / ReasonML 文法と標準ライブラリを採用した JavaScript トランスパイラである BuckleScript が ReScript に改称した。 公式サイトによると改称の理由は、 Unifying the tools in one coherent platform and core team allows us to build features that wouldn’t be possible in the original BuckleScript + Reason setup. (単一のプラットフォームとコアチームにツールを統合することで従来の BuckleScript + Reason 体制では不可能であった機能開発が可能になる) とのこと。要は Facebook が主導する外部プロジェクトである ReasonML に依存せずに開発を進めていくためにフォークするという話で、Chromium のレンダリングエンジンが Apple の WebKit から Google 主導の Blink に切り替わったのと似た動機である (プログラミング言語の分野でも Object Pascal が Pascal を逸脱して Delphi Language になったとか PLT Scheme (の第一言語) が RnRS とは別路線に舵を切って Racket になったとか、割とよくある話である。) 公式ブログの Q&A によると OCaml / ReasonML 文法のサポートは継続され、既存の BuckleScript プロジェクトは問題なくビルドできるとのこと。ただし現時点で公式ドキュメントは ReScript 文法のみに言及しているなど、サポート水準のティアを分けて ReScript 文法を優遇することで移行を推進していく方針である。 上流である OCaml の更新は取り込み、AST の互換性も維持される。将来 ReScript から言語機能が削除されることは有り得るが、OCaml / ReasonML からは今日の BuckleScript が提供する機能すべてにアクセスできる。 現時点における ReScript の

多分週刊チラシの裏 (Oct 12 - 18, 2020)

プログラミング言語のエネルギィ効率性 おなじみ Computer Language Benchmark Game にある言語のうちプロプライエタリな Smalltalk を除く 27 言語の、時間効率性と空間効率性に加えて「エネルギィ効率性」を検証したという研究。 結果は大方の予想を外れない (コンパイラ言語 - VM 言語 - インタプリタ言語の序列) のだが、言語毎によって単位時間あたりのエネルギィ効率 (換言すると CPU 最適化性能) が異なるので「速ければより省エネ」とは必ずしも言えないことや、最大メモリ消費量は言語のパラダイムによって大方が決まり、エネルギィ効率とはほとんど相関がない (ので Java でもエネルギィ効率は高い) ことなど面白い事実が見られる。 『アメリカのインターネット』の終焉 1994 年に Netscape が設立されたとき、世界にはおよそ一億台の PC があり、その半数は合衆国にあった。 WWW はスイスで開発されたしコンピュータは英国の発明だが、インターネットは米国製だった。 米国の企業がその課題を与え、重要な製品とサービスを作り、規制や言論は米国の立場、文化、法が支配した。 (引用者訳) 合衆国政府による TikTok 分割騒動に寄せての現在と未来のインターネットの話。 今日のインターネットの利用者のうち 80 - 90% は米国外の住人である。中国のスマートフォン台数は米国と欧州を合わせたよりも多く、ソフトウェア・スタートアップの半数はシリコンバレーの外で起きている。 テクノロジーは規制産業になったが、その規則はもはや合衆国の一存では決まらないのである。 まつもとゆきひろのツイッターを見てRuby使うのをやめようと思った Ruby の原開発者にして「寛大なる就寝独裁官 (BFDL)」の Twitter における言動が差別主義とは言えないまでもマイクロアグレッションに満ちていたので製品としての Ruby にも悪印象がついたという話。 不要に攻撃的な人やコミュニティから距離を置く理性は心身の健康のためにも重要である。 FTP のフェードアウト Chrome をはじめとする Web ブラウザにおいてファイル転送プロトコル (FTP) のサポート終了が迫っていることに寄せて、半世紀に渡ってインターネットの

OCaml で Web フロントエンドを書く

要旨 フロントエンド開発に Elm は堅くて速くてとても良いと思う。昨今の Flux 系アーキテクチャは代数的データ型と相性が良い。ところで工数を減らすためにはバックエンドも同じ言語で書いてあわよくば isomorphic にしてしまいたいところだが、Elm はバックエンドを書くには現状適していない。 OCaml なら js_of_ocaml でエコシステムを丸ごとブラウザに持って来れるのでフロントエンドもバックエンドも無理なく書けるはずである。まず The Elm Architecture を OCaml で実践できるようにするため Caelm というライブラリを書いている。俺の野望はまだまだこれからだ (未完) Elm と TEA について Elm というプログラミング言語がある。いわゆる AltJS の一つである。 ミニマリスティクな ML 系の関数言語で、型推論を持ち、型クラスを持たず、例外機構を持たず、変数の再代入を許さず、正格評価され、代数的データ型を持つ。 言語も小綺麗で良いのだが、何より付属のコアライブラリが体現する The Elm Architecture (TEA) が重要である。 TEA は端的に言えば Flux フロントエンド・アーキテクチャの変種である。同じく Flux の派生である Redux の README に TEA の影響を受けたと書いてあるので知っている人もいるだろう。 ビューなどから非同期に送信される Message (Redux だと Action) を受けて状態 (Model; Redux だと State) を更新すると、それに対応して Virtual DOM が再構築されビューがよしなに再描画され人生を書き換える者もいた——という一方向の流れはいずれにせよ同じである。 差異はオブジェクトではなく関数で構成されていることと、アプリケーション外部との入出力は非同期メッセージである Cmd / Sub を返す規約になっていることくらいだろうか。 後者は面白い特徴で、副作用のある処理はアプリケーションの外で起きて結果だけが Message として非同期に飛んでくるので、内部は純粋に保たれる。つまり Elm アプリケーションが相手にしないといけない入力は今現在のアプリケーションの完全な状態である Model と、時系列イベ