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

Perl のサブルーチンシグネチャ早見表

Perl のサブルーチン引数といえば実引数への参照を保持する特殊配列 @_ を手続き的に分解するのが長らくの伝統だった。これはシェルの特殊変数 $@ に由来する意味論で、おそらく JavaScript の arguments 変数にも影響を与えている。

すべての Perl サブルーチンはプロトタイプ宣言がない限りリスト演算子なので、この流儀は一種合理的でもあるのだが、実用的にそれで良いかというとまったくそうではないという問題があった; 結局大多数のサブルーチンは定数個の引数を取るので、それを参照する形式的パラメータが宣言できる方が都合が良いのである。

そういうわけで実験的に導入されたサブルーチンシグネチャ機能により形式的パラメータが宣言できるようになったのは Perl 5.20 からである。その後 Perl 5.28 において出現位置がサブルーチン属性の後に移動したことを除けば Perl 5.34 リリース前夜の今まで基本的に変わっておらず、未だに実験的機能のままである。

おまじない

シグネチャは前方互換性を持たない (構文的にプロトタイプと衝突している) 実験的機能なのでデフォルトでは無効になっている。

そのため明示的にプラグマで利用を宣言しなければならない:

use feature qw/signatures/;
no warnings qw/experimental::signatures/;

どの途みんな say 関数のために使うので feature プラグマは問題ないだろう。実験的機能を断りなしに使うと怒られるので、no warnings で確信犯であることをアピールする必要がある。

これでプラグマのスコープにおいてサブルーチンシグネチャ (と :prototype 属性; 後述) が利用可能になり、従来のプロトタイプ構文が無効になる。

使い方

対訳を載せておく。シグネチャの方は実行時に引数チェックを行うので厳密には等価でないことに注意:

# Old School use feature qw/signatures/
1 sub f { my ($x) = @_; ... } sub f($x) { ... }
2 sub f { my ($x, undef, $y) = @_; ... } sub f($x, $, $y) { ... }
3 sub f { my ($x, $y) = @_; $y //= ...; ... } sub f($x, $y = ...) { ... }
4 sub f { my ($x, @rest) = @_; ... } sub f($x, @rest) { ... }
5 sub f { my ($x, %rest) = @_; ... } sub f($x, %rest) { ... }
6 sub f(&@) { my ($f, @args) = @_; ... } } sub f :prototype(&@) ($f, @args) { ... }

なんのことはない、今までプログラマがやっていた @_ の分解を自動でやってくれるようになっただけである。

1, 2 は定数個の形式的パラメータを持つ。互換性やら API の一貫性やらのために使われない形式的パラメータが必要な場合は良くあるが、その場合 2 のように変数名を省略できる。

3 はオプショナル引数を持っている。当然だがオプショナル引数は形式的パラメータ列の右側に寄せる必要がある; sub ($x = 42, $y) { ... } のように右に必須引数を残してより左の形式的パラメータをオプショナルにはできない。 またオプショナル引数のデフォルト値は Python と同じく呼び出し毎に解決される; 元々 $x //= calc_default(); などとやっていたのと同じと思って良い。

これら有限個の形式的パラメータを持つシグネチャが宣言された場合、単に変数の初期化だけでなくその個数も確認される。つまり例の 1 と 2 はそれぞれ厳密に 1 個と 3 個、3 は 1 個以上 2 個以下の実引数で呼び出されなければならない。それより多かったり少なかったりすると実行時例外が発生する (プロトタイプと違いコンパイル時エラーにはならない。) 旧来の方法のように超過した実引数を単に無視したい場合は、後述する slurp 引数と 2 の無名パラメータを組み合わせることができる: sub f($x, @) { ... }

4, 5 はリスト演算子である。任意個の実引数を取り、形式的パラメータからあぶれた値は最後に置かれた配列ないしハッシュが丸飲みする。これを Raku と同じく slurp 引数と呼ぶ。 要するに Python の *args とか **args と同じものだが、Perl 5 は名前付き引数と位置的引数の意味論上の違いを持たない (e.g., foo => 'bar'qw/foo bar/ の構文糖衣に過ぎない) ので一つのシグネチャが配列とハッシュ両方の slurp 引数を持つことはできない。 またハッシュの場合はそれが引き受けた実引数が偶数個でない場合に実行時例外が発生する。

6 はプロトタイプと同時に宣言する場合である。プロトタイプにはサブルーチン呼び出しの統語論や意味論を変える特殊な宣言がある; 例えばプロトタイプで第一引数に & を宣言したサブルーチンは組み込み関数の eval/grep/map/sort のようにブロックを無名サブルーチンへのリファレンスとして受け取るという文法上の特殊規則があるが、シグネチャにそのような機能はない。そのため両方を宣言する必要がある。 先述したようにプロトタイプの本来の構文 (サブルーチン名 (あれば) の後に () で囲んで宣言する) はシグネチャと衝突し得るので use feature qw/signatures/ すると使えなくなる。その代替として :prototype 属性がインポートされるので、サブルーチンにこの属性をつけることでプロトタイプを定義できる。Perl 5.28 以降シグネチャはサブルーチン属性より後に順番が入れ替わっているので注意。ちなみに本来のプロトタイプはサブルーチン属性より前に出現する。

なおプロトタイプとシグネチャの整合性は検査されない。矛盾する記述をした場合はコンパイル時エラーと実行時例外でどうやっても呼べないサブルーチンになる。

最後に、いずれの場合にも @_ は依然として存在し、すべての実引数にアクセス可能である。

コメント

このブログの人気の投稿

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 ...

多分週刊チラシの裏 (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...

多分週刊チラシの裏 (Sep 28 - Oct 04, 2020)

Chrome Web Store が有料 Chrome 拡張の取扱を終了 Chrome Web Store で提供されている有料 Chrome 拡張及びアプリ内課金 API の両方が 2021 年 1 月いっぱいで廃止される。 開発者はそれまでに代替となるサードパーティの課金 API に移行し、購入済ライセンスの移行手段も用意する必要がある。 この決定の発表時点で新規の有料ないしアプリ内課金のある Chrome 拡張の新規登録は終了している。実際のところ 2020 年 3 月時点で既に「一時的に」停止されており、その措置が恒久化されただけとの由。 シェルスクリプティングには長いオプションを使え 「短いオプション (e.g., -x ) はコマンドライン上での略記である。スクリプトにおいては自分や将来の同僚のためにも長いオプション (e.g., ---do-something ) を与える方が理解が容易だろう」という主張。 異論の余地なく正論である。 CobWeb - COBOL to WebAssembly Compiler COBOL から WebAssembly へのコンパイラ。いやマジで。 Cloudflare が何を思ったか同社のサーバレス環境である Workers に COBOL 対応を追加した際 の成果物である。 COBOL から C へのトランスレータである GNU COBOL と C コードをコンパイルして WebAssembly を出力する Emscripten から成っており、他の言語に比べて軽量なバイナリを生成するとのこと。 「ウチではそんな風にはやらないんだ (“We don’t do that here”)」 昨今ソフトウェア開発のコミュニティでも Code of Conduct を用意するところが増えてきたが、コミュニティの文化を明文化するのは難しい。 長大な「べからず集」は息苦しいし、肯定的なガイドラインは時に抽象的で実効的に使えない。問題となるようなふるまいの動機が善意であった場合は特にそうだ。 仮に優れたガイドラインがあっても、それに基いて人を実際に咎めるのは骨が折れることである。初中やればコミュニティ内でも疎まれる。 話の分かる相手ならそれでもまだ説得する意義もあるが、Web 上の対話で当事者双方が納得し合っ...

Mac から iPhone のカメラを起動して写真を直接取り込める

Via: The Verge ID セルフィーや (物理) 書籍のページスキャンなど携帯電話のカメラを使って写真を取り込むことは日常的な所作になっているが、写真の使い途が何かの申し込み用 Web フォームなどで iPhone より Mac の方が操作し易いときなどは億劫だ。Mac 組込の FaceTime カメラは 720p とか 1080p しかなくて非力すぎ、かといって iPhone で一旦撮影したものを Photos から探して AirDrop するのも面倒である。 実は macOS Mojave / iOS 12 以降には Continuity Camera という機能がある。これを使うと Apple 製の Mac アプリケーションから iPhone / iPad のカメラを起動して、余計な中間コピーを残すことなく写真を Mac に転送できる。 使い方は簡単で、対応している Mac アプリケーションのコンテキストメニューに “Import (or Insert) from iPhone (or iPad)” という項目がある。“Take Photo” だと一枚、“Scan Documents” だと複数の写真を (歪み補正しつつ) 連続で撮影して転送できる。 対応 Mac アプリケーションは Finder のほか iWork (Keynote, Numbers, Pages), Mail, Messages, Notes, TextEdit となっている、のだが実は Preview でも使える。同様にコンテキストメニューあるいは “File” メニューから起動できる。

Perl 5 to 6 - MAINサブルーチン

これはMoritz Lenz氏のWebサイト Perlgeek.de で公開されているブログ記事 "Perl 5 to 6" Lesson 14 - The MAIN sub の日本語訳です。 原文は 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 14 - MAINサブルーチン SYNOPSIS # ファイル doit.pl #!/usr/bin/perl6 sub MAIN($path, :$force, :$recursive, :$home = '~/') { # do stuff here } # コマンドライン $ ./doit.pl --force --home=/home/someoneelse file_to_process DESCRIPTION サブルーチン呼び出しと典型的なUNIXプログラムのコマンドラインからの起動は、見た目にはとてもよく似ています: 位置的な引数やオプション、名前付き引数を与えられます。 この類似点のおかげで、Perl6はコマンドラインを処理してサブルーチン呼び出しに変換してくれます。 スクリプトは通常通り実行され(この時点で @*ARGS に格納されているコマンドライン引数を書き換えることもできます)、その後もし存在すれば MAIN サブルーチンが呼び出されます。 コマンドライン引数が MAIN サブルーチンの形式的パラメータにマッチしない場合、自動的に生成されたUsageが表示されます。 コマンドラインオプションはサブルーチン引数に以下のようにマップされます: -name :name -name=value :nam...