Perl

Perl の文法上の新機能が使える feature プラグマ詳解

Perl5 は 5.12 以降、ほぼ1年ペースでメジャーバージョンアップしています。つまり 5.x の偶数 x が +2 されています。

Perl は後方互換性をとても重視した言語で、メジャーバージョンアップで過去の Perl プログラムが動かなくなることはほぼありません。また、バージョンアップによって変わる部分の多くが、速度的な改善であったり、限定的な状況におけるセキュリティ改善だったりといった、インターフェースにかかわらない部分です。

とはいえ、Perl も後方互換性を崩さないよう配慮した上で、実験的な機能を追加することがあります。この記事ではそれら実験的な機能の登場バージョンなどをまとめました。

  • 文字コード関連のいくつか (unicode_eval, fc など)のうまい解説ができていないので、現状解説を空欄にしてあります。後日追記したところで、ストックしている方に通知を送ります。

新たな文法上の機能はどう使う?

Perl 5.10 で追加されたいくつかの機能については feature プラグマを use することで使うことができます。この記事では feature プラグマによって使える機能を解説します。

各種実験的な機能が使いたい場合は、 feature プラグマとは別に
experimental プラグマを use して使います。この記事では feature
プラグマのみの解説とし、experimental プラグマについては別記事で触れます。

feature による Perl 5.10 以降の新機能

feature プラグマは、Perl が新たに提供することになった構文上の機能を、既存の Perl プログラムを壊すことなく選択的に導入するためのものです。

使い方は perldoc feature日本語版最新英語版) を参照下さい。

use feature qw(使いたい1 使いたい2 ...);

といった感じで指定します。例えば feature が提供する say 関数を使いたい場合は

use feature qw(say);

といった感じで指定します。

このバージョンまでに追加された機能を使いたい(かつ、このバージョン以下の perl での動作を禁止したい)という場合には、原則的に

use v5.20;

などと書くと良いです。この場合、使用している perl インタプリタのバージョンがこの指定バージョン以上である必要があります。

「原則的に」の例に漏れるもの (array_base) は、下記の解説で触れています。

なお、feature はuse したスコープに限定されます。

# 上で use v5.10 や use feature 等をしていない
{
    use feature qw(say);
    say "Hello."; # OK
}
say "Good Morning!"; # NG
名前 どういう機能か いつから 備考
say 末尾改行付きprint 5.10
state 二度以降初期化されないmy 5.10
switch given when による switch 文 5.10 非推奨
unicode_string 5.12 5.14で大部分実装、5.16で一部拡張
unicode_eval 5.16
evalbytes 5.16
current_sub 自分自身を __SUB__ トークンで参照できる 5.16
array_base 配列の添字を0始まり以外にする 5.16 非推奨use v5.16; をすると use ではなく no される
fc 5.16
lexical_subs レキシカルサブルーチン 5.18 5.26から警告無し
postderef 後置デリファレンス 5.20 5.24から警告無し
postderef_qq 後置デリファレンスをダブルクォート内で展開 5.20 postderef 同様
signatures サブルーチンシグネチャ(仮引数) 5.20
refaliasing リファレンスによる別名変数定義 5.22
bitwise ビット演算子を数値専用と文字列専用に分ける 5.22
declared_refs リファレンスの直接宣言 5.26

say - 末尾改行付き print

解説の通りです。

いくつかの言語では println 、PHP でいう echo 、Ruby でいう puts のようなものです。

間接オブジェクトスロットにファイルハンドルが置かれることを想定しなければ(つまり say {$fh} "Hello" という形での呼び出しではないということ)、誰もが簡単に書くことができます。

sub say {
    print @_, "\n";
}

state - 二度目以降初期化されない my

state は、カウンターサブルーチンなど、状態を持ったサブルーチンを定義する時に使うものです。state は特殊な my として扱われ、定義できるものは my と同じレキシカル変数ですが、同じ行で二度以降初期化されないという特性を持っています。

例えば、呼び出すごとに返却値の数値が増えるカウンターサブルーチンを定義してみましょう。

### これは間違い
sub count {
    my $count = 0;
    return ++$count;
}

print count(), "\n"; # 1
print count(), "\n"; # 1
print count(), "\n"; # 1

この場合、 my $count = 0; の行は count() を呼び出すたびに初期化処理が入ります。

今までの構文でカウンターを実現するには、 my $count は外に出しつつ定義します。

my $count = 0;
sub count {
    return ++$count;
}

print count(), "\n"; # 1
print count(), "\n"; # 2
print count(), "\n"; # 3

count サブルーチン以外の外部( my $count = 0 の下にある行)から $count を操作できることを気にするのであれば、全体を無名ブロックで囲うと良いです。

{
my $count = 0;
sub count {
    return ++$count;
}
}

print count(), "\n"; # 1
print count(), "\n"; # 2
print count(), "\n"; # 3

この無名ブロックで my 宣言と sub サブルーチン宣言を囲う書き方は古くからの Perl のイディオムともいえるものですが、初学者が混乱する構文であるかもしれません。

これを同様のことを簡素に書けるようにしたのが state です。

use feature qw(state);
sub count {
    state $count = 0;
    return ++$count;
}

print count(), "\n"; # 1
print count(), "\n"; # 2
print count(), "\n"; # 3

もちろん、state 宣言の行と同じ文で行われた代入が一度だけということなので、別の行で $count に代入操作を入れると count サブルーチンの中の $count の値は変わってしまうことに注意して下さい。

use feature qw(state);
sub count {
    state $count; # state 宣言の行は全部通して一度だけ評価される
    $count = 0;   # ここは通常の代入の行なので何度も評価される
    return ++$count;
}

print count(), "\n"; # 1
print count(), "\n"; # 1
print count(), "\n"; # 1

switch - given-when とスマートマッチ

switch は、多くの言語でいう switch-case 構造を再現するものです。

use feature qw(switch say);
my $arg = shift;
given ($arg) {
   when (1)         { say "one"; }
   which (/^Hello/) { say "Hello!"; }
   default          { say "How are you?"; }
}

多くの言語にある switch-case 文と似ていますが、 swtich にあたる given で指定された $arg が、各 when で指定された値との比較がスマートマッチ ~~ という二項演算子によって行われます。

use feature qw(switch say);
my $arg = shift;
if ($arg ~~ 1) {
    say "one";
} elsif ( $arg ~~ /^Hello/) {
    say "Hello!";
} else {
    say "How are you?";
}

しかし、Perl 5.10.1 で導入されたスマートマッチは、当時から仕様が複雑だったりといった問題が指摘される機能で、Perl 5.18 でいったん非推奨となりました

そのため、スマートマッチとともに導入された given-when も、スマートマッチと共に Perl5.18 より非推奨となっています。

switch を使用する場合も、スマートマッチ関連の警告が出るので

no warnings "experimental::smartmatch";

と書いて警告を抑止する必要があるかもしれません。スマートマッチについての解説をよく読んで、使用する場合も様々なリスクを理解する必要がありそうです。

unicode_string

(stub)

unicode_eval と evalbytes

(stub)

current_sub - 自分自身を __SUB__ トークンで参照できる

Perl でもサブルーチンを再帰で書くことがあります。

#!/usr/bin/perl

use strict;
use warnings;
use feature qw(say);

say fib(5);

sub fib {
    my $n = shift;
    if ( !defined $n || !length $n || $n =~ /\D/ ) {
        die "fib: 1st argument is required as digit.\n";
    } elsif ( $n == 0 || $n == 1 ) {
        return 1;
    } else {
        return fib($n-1) + fib($n-2);
    }
}

上記は平凡なフィボナッチ数列の第$n項を求めるサブルーチン(関数)です。

例えば、初項と第二項を事前に選んだフィボナッチ数列を求めるサブルーチンを返すサブルーチンを書くとしたらどのように書くと良いでしょうか。

#!/usr/bin/perl

use v5.10;
use strict;
use warnings;

my $fib = generate_fibonacci_sequence(3, 7); # 3 7 10 17 27 44 ...
say $fib->(5); # 44

sub generate_fibonacci_sequence {
    my ($first, $second) = @_;
    for ($first, $second) { # defined 等、暗黙の $_ を参照していることに注意
        if ( !defined || !length || !m{^-?(?:\d+)(?:\.\d+)?$} ) {
            die "generate_fibonacci_sequence: 1st and 2nd arugment is quired as integer.\n";
        }
    }
    my $fib; $fib = sub {
        my $n = shift;
        if ( !defined $n || !length $n || $n =~ /\D/ ) {
            die "fib: 1st argument is required as digit.\n";
        } elsif ( $n == 0 ) {
            return $first;
        } elsif ( $n == 1 ){
            return $second;
        } else {
            return $fib->($n-1) + $fib->($n-2);
        }
    };
    return $fib;
}

クロージャと言われるような書き方で対応しました。my $fib; $fib = ... という風に宣言(my) と代入(=) を別の文に分けているのは、代入が右結合なので、左辺の宣言評価の前に右辺のサブルーチンリファレンスが評価されることになり、その中にある $fib はまだ宣言されていないことで use strict によって未宣言エラーとなるためです。

最初の簡素な fib() サブルーチンの構造を包含するように generate_fibonacci_sequence() は複雑なサブルーチンとなりましたが、再帰呼び出しを使っている発想は同様です。

「無名関数」とも呼ばれるサブルーチンリファレンスで再帰呼び出しを行う必要がありましたが、今回は無名といいつつ、すぐに $fib という「名前」を付けることができたので、これを再帰呼び出しのネタとして使うことができました。

サブルーチンリファレンスが必要とされる場面で、そのサブルーチンリファレンス自体が再帰呼び出しロジックを必要とする場合には、上記のように即座にスカラー変数に代入して「名前」を付けることで対応することができます。

しかし、サブルーチンを返却するサブルーチンを返却するサブルーチン…といった多階層構造になったり、ある程度大掛かりなオブジェクトのメソッドにコールバックを渡したり…といった場面において、「名前」を付けることが手間になる場面もあります。

そのような場合、サブルーチンが自分自身を指す名前が既に無くとも、__SUB__ と書くことで自分自身のリファレンスを取得できる機能が current_sub です。

#!/usr/bin/perl

# どちらかの use を書くと current_sub が有効になる
use v5.16;
use feature qw(say current_sub);

use strict;
use warnings;

my $fib = generate_fibonacci_sequence(3, 7); # 3 7 10 17 27 44 ...
say $fib->(5); # 44

sub generate_fibonacci_sequence {
    my ($first, $second) = @_;
    for ($first, $second) {
        if ( !defined || !length || !m{^-?(?:\d+)(?:\.\d+)?$} ) {
            die "generate_fibonacci_sequence: 1st and 2nd arugment is quired as integer.\n";
        }
    }
    return sub {
        my $n = shift;
        if ( !defined $n || !length $n || $n =~ /\D/ ) {
            die "fib: 1st argument is required as digit.\n";
        } elsif ( $n == 0 ) {
            return $first;
        } elsif ( $n == 1 ){
            return $second;
        } else {
            return __SUB__->($n-1) + __SUB__->($n-2);
        }
    };
}

__SUB__ が使えることになったため、$fib の宣言と代入が省かれてシンプルになりました。

my $fib; $fib = sub { ... }; という宣言と代入を分ける書き方は AnyEvent 関連モジュール等、コールバックを多用する構造で多用する書き方ではありますが、Perl の初学者や中級者には初見殺し(宣言と代入の概念をわかりやすく書いた文献がほぼないからとも言えますが)でもあるので、__SUB__ による書き方は簡潔さだけでなく初学者にも優しいと感じます。

Perl には古くからサブルーチン自身もしくは呼び出し元パッケージを調べる caller 組み込み関数がありますが、これとは違う用途で使われるものです。

array_base - 配列の添字を0始まり以外にする

多くのプログラム言語の例にもれず、Perl も配列の添字の始まりは (1ではなく) 0 です。

ただ、Perl が登場する前に存在していた古い AWK や Fortran といったプログラム言語では、配列の添字の始まりは 1 だったとのことで、その振る舞いを Perl で再現するため、配列の添字の始まりを変えるための特殊なグローバル変数 $[ というものがありました。

# Perl 5 以降で
# 添字を1始まりにする
$[ = 1;

この $[ の詳細は perlvar の当該項目を参照下さい。

そもそも、Perl の添字の始まりを変更することは、他の外部ファイルなどへの副作用が大きいと恐れるのは自然なことで、この添字を変更する $[ の使用は Perl 5.12 で非推奨となっています。ともかく私も使ったことがなく(添字が 0 始まりで困ったことがない)、起こりうる副作用や混乱(プログラミングの共同作業者に誤解を与えるところから)を考えると怖くて使えません。

ここからは Perl 5.16 以降の話です。

Perl 5.16 以降では $[ 変数の動作は arybase プラグマが制御しています。$[ に代入しようとすると、裏側で自動的に use arybase; が行われます。

#!/usr/bin/env perl

use strict;
use warnings;

use feature qw(say);

# 以下の代入が発生する直前に use arybase; が暗黙で呼ばれる
$[ = 1;

my @array = (qw(first second third fourth));

say "array[1] = $array[1]"; # first

しかし、上記のプログラムを実行すると警告が出ます。

Use of assignment to $[ is deprecated at feature_example_array_base.pl line 8.
array[1] = first

arybase プラグマが対応することになったとはいえ、要するに非推奨というわけですね。

この $[ の機能を完全に封じたいと考えるのは自然で、これを行うのが Perl 5.16 以降で使えることになった no feature qw(array_base); プラグマです。肯定的なプラグマ呼び出し use ではなく、否定的なプラグマ呼び出し no なのがポイント。

#!/usr/bin/env perl

use strict;
use warnings;

use feature qw(say);
no  feature qw(array_base);

$[ = 1;

my @array = (qw(first second third fourth));

say "array[1] = $array[1]";

こう書くと、$[ = 1; の代入(具体的には 0 以外の代入)が発生した時点で実行時エラーが発生します。

Assigning non-zero to $[ is no longer possible at feature_example_array_base.pl line 9.

say などは、その登場バージョン以上のバージョン番号で use v5.10; とすると use feature qw(say); などとされたと同じとみなされて使えるようになります。しかし array_base については特殊で、それが登場した perl-5.16 以降で実は use v5.16; とすると array_base に関しては use feature qw(array_base); ではなく no feature qw(array_base); されたとみなされることになります。

ただ、use v5.16; と書きたいけれど、深遠な事情で $[ = 1; はしたいという場合に、use feature qw(array_base);$[ = 1; を書くことを許可するようにできるというものです。

#!/usr/bin/env perl

use strict;
use warnings;

use v5.16;
use feature qw(say);
use feature qw(array_base);

$[ = 1;

my @array = (qw(first second third fourth));

say "array[1] = $array[1]";

use feature は複数の機能をまとめて書いてもいいですし、上記のように行を分けて書いても良いです。

use v5.16; 時点で $[ = 1; は実行時エラーとなりますが、use feature qw(array_base); をすることで実行時エラーを回避して、arybase プラグマを利用して当該機能を Perl 5.16 以降でも使用することができるという流れです。

Use of assignment to $[ is deprecated at feature_example_array_base.pl line 10.
array[1] = first

とはいえ、use feature qw(array_base); したところで非推奨なことに変わりません。

実際に内部的にどのようなコードが実行されているのかは、B::Deparse を使うことでわかります。

$ perl -e 'use B::Deparse; use v5.16; use feature "say"; say B::Deparse->new("-p", "-sC")->coderef2text(sub { 1; })';
{
    use strict;
    use feature 'current_sub', 'evalbytes', 'fc', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
    no feature 'array_base';
    1;
}

use v5.16; の後に何らかの use feature があると、実際にどの feature が有効無効になっているのか、B::Deparse で見ることができます。

fc - 文字のfolding

(stub)

lexical_subs レキシカルサブルーチン

レキシカルサブルーチンとは my sub foo といった、書かれたスコープ内でのみ有効な新しいサブルーチンの書き方を導入するものです。

lexical_subs は、Perl 5.18 から Perl 5.24 までは

The lexical_subs feature is experimental

といった警告が出てきてしまいます。理解して使っているのでこれを抑止したいという場合には

no warinigns "experimental::lexical_subs";

と書きます。

Perl 5.26 から上記警告が出なくなりました。

#!/usr/bin/env perl
use strict;
use warnings;

use feature qw(lexical_subs say);

my $n = 1;

if ( $n == 1 ) {
    my sub info {
        my @args = @_;
        say "[info] @args";
    }
    info("foo");
}

info("bar");

これを実行すると

[info] foo
Undefined subroutine &main::info called at tmp/feature_example_lexsub.pl line 17.

といった表示となります(上述の通り 5.24 までの Perl では experimental 旨警告が出る場合もあります)。if のスコープの中でのみ有効な info は実行されるものの、そのスコープの外で info を呼び出そうとしたらエラーとなるサンプルです。

レキシカルサブルーチン my sub foo は、今まではサブルーチンリファレンスで代用できていたものです。

#!/usr/bin/env perl
use strict;
use warnings;

use feature qw(say);

my $n = 1;

if ( $n == 1 ) {
    my $info = sub {
        my @args = @_;
        say "[info] @args";
    }
    $info->("foo");
}

$info->("bar"); # $info が定義されていないことは明白なので、ここでエラーとなる

私も、サブルーチンリファレンスを使わずあえてレキシカルサブルーチンを使うとよい上手い使いどころがわからず、様子見状態です。

変数の my 宣言以外にも特殊な my である state やグローバル変数の宣言を行う our があるように、use feature qw(lexical_subs); では my sub foo 以外にも、それに対応した state sub fooour sub foo といった記法を使うことができます。

state sub foo については、変数の state と同様にそのスコープ内で一度しか初期化されないサブルーチンを定義します。うまい例が思いつかなかったので例は省略しますが、 forwhile の中で繰り返されるループ内に my sub foo があると、都度サブルーチン初期化のコストがかかるわけで、 state sub foo が求められる場面があるかもしれません(その前に my sub foo 自体に意義を見出さなければなりませんが)。

our sub foosub foo と全く同じ意味だと思います。 our が意味するところはグローバル変数 == パッケージと紐付いた変数であるわけです。この辺りはPerl のグローバル変数やレキシカル変数について - Qiitaを参照下さい。

サブルーチン宣言のブロック中にサブルーチン宣言を書いた場合、コンパイルは通りますが、内側のサブルーチンは外側のサブルーチンから出て並列で書かれたかのようにコンパイルされます。この挙動をサブルーチンの巻き上げと呼ぶ人もいます。この際、外側のサブルーチンのブロックが持つレキシカル変数を内側のサブルーチンが共有していると、意味が曖昧になって警告が出ます。

#!/usr/bin/env perl

use strict;
use warnings;

use feature qw(say lexical_subs);

sub handler {
    my $handler_call_count = 1;
    # このように sub calc を書いても、コンパイル時には
    # sub handler と sub calc を入れ子ではなく並列に書いたように解釈される
    sub calc {
        my $n = shift;
        return $n * $handler_call_count++;
    }
    say calc(20);
    say calc(-26);
}

handler();

このスクリプトを実行すると

Variable "$handler_call_count" will not stay shared at feature_example_globalsub.pl line 14.
20
-52

と警告が表示されます。

上記例では sub calc でも our sub calc でも同様の警告が表示されますが、 my sub calcstate sub calc であれば変数が曖昧に共有されることもなく、警告は出ません。

handlercalc は入れ子のように書かれていながら、実際は並んで書かれたかのように解釈されるものの、そのように解釈すると、 handler の外に出てしまった calchandler の関数スコープの中にある $handler_call_count を参照しようとする部分が曖昧となってしまうためです。

もちろん、返り値としてサブルーチンリファレンス(関数参照)を返せば、 handler 内の $handler_call_counthandler が呼び出すたびに別途生成され、モダンなプログラミング言語で活用されるクロージャ的動作となります。

#!/usr/bin/env perl

use strict;
use warnings;

use feature qw(say lexical_subs);

# handler はカウンターを返す
sub handler {
    my $handler_call_count = 1;
    # このように sub calc を書いても、コンパイル時には
    # sub handler と sub calc を並べて書いたように解釈される
    return sub {
        return $handler_call_count++;
    }
}

my $counter_a = handler();
my $counter_b = handler();


say $counter_a->(); # 1
say $counter_b->(); # 1
say $counter_a->(); # 2
say $counter_a->(); # 3
say $counter_b->(); # 2

postderef と postderef_qq - 後置デリファレンス

Perl では配列リファレンスやハッシュリファレンスのデリファレンスにアロー記法 -> を使います

my $first_line = $response->{body_lines}->[0];

上記 $response のデータ構造だと、レスポンスボディの最初の行」といった書き方。 $response がハッシュリファレンスで、そのキー(key) body_lines に対応する値(value)が配列リファレンスで、行ごとに(配列リファレンスがさす実態としての)配列の要素となっていると読めます。

たとえば、行番号として添字を指定するのではなく繰り返し指定したい場合には、 for で繰り返し処理を書きます。

for my $line (@{$response->{body_lines}}) {
    ...
}

とはいえ、プログラムを書く思考の流れ的にはまず $response->{body_lines} と書いた後で、「そうそうこれは配列リファレンスで、その要素全体をリストでほしいんだった(リストコンテキストに配列を置くとリストが得られる)」と思い立って、カーソルを左側に戻して @{ ... } と書くことがたびたびあります。かくいう私もそういう行動をしています。

であれば、思考の流れをそのまま左から右へ書いていけると嬉しいという考えのもと生み出されたのが、後置デリファレンス (postfix dereference) です。

後置デリファレンスは use feature qw(postderef); とすることで使うことができ、

@{$response->{body_lines}}

use feature qw(postderef); # 離れた場所で定義されていても OK

$response->{body_lines}->@*

と書くことができるようになります。

use feature qw(postderef);

for my $line ($response->{body_lines}->@*) {
    say $line;
}

配列リファレンス以外にも記法があります。下記例は perlref より。

  $sref->$*;  # same as  ${ $sref }
  $aref->@*;  # same as  @{ $aref }
  $aref->$#*; # same as $#{ $aref }
  $href->%*;  # same as  %{ $href }
  $cref->&*;  # same as  &{ $cref }
  $gref->**;  # same as  *{ $gref }

昔からの Perl プログラマの間には「後置デリファレンスはうけつない」という人が多いように感じますが、たぶん ->@** が何を意味しているのかわからないという部分が大きいのかなと思います。

この * 部分には、いわゆるスライス構文を置くことができます。

use feature qw(postderef);

# 5行目から10行目までが欲しい
my @part_lines = $response->{body_lines}->@[4..9];

postderef に似た postderef_qq は、後置リファレンスをダブルクォート(もしくはそれと同等な qq{} など)の中で展開するものです。

print "array is @array\n"; # @array が空白区切り(実際は変数 $" 区切り)で内挿される

use feature qw(postderef postderef_qq);
print "array is $response->{body_lines}->@*";

後置デリファレンスがない時代に "$foo->{bar}->@*" 等と書かれた文字列を構文エラーにしてしまわないため、postderef と postderef_qq が分かれています。こんな部分まで後方互換性を気にしてくれるのは、Perlならではと言えましょう。

後置デリファレンスの考え方については、prian d foy 氏による以下の記事がわかりやすいです。

また、詳細は最新の perlref を参照下さい。

signatures - サブルーチンシグネチャ(仮引数)

Perl には多くのプログラミング言語にある関数の仮引数がないということがよく槍玉に挙げられます。

sub add {
    my ($left, $right) = @_;
    # もしくは
    #     my $left = shift;
    #     my $right = shift;
    retrun $left + $right;
}

例えば JavaScript であれば

function add(left, right) {
    return left + right;
}

と仮引数を使って書けるわかりやすさを Perl に導入したものがサブルーチンシグネチャです。

use feature qw(signatures say);

sub add ($left, $right) {
  return $left + $right;
}

say add(5, 7);

ただし Perl 5.26 現在、そのままでは

The signatures feature is experimental

といった警告が出てきてしまいます。理解して使っているのでこれを抑止したいという場合には

no warnings "experimental::signatures";

と書きます。

Perl にはプロトタイプ宣言というサブルーチンシグネチャに似た構文が大昔からあり、サブルーチンシグネチャを使う場合にはプロトタイプ宣言と混乱しない使い方が求められます(主にプロジェクトメンバーに対して)。

プロトタイプ宣言の良し悪しはこの記事では割愛しますが、サブルーチンシグネチャとプロトタイプ宣言を同時使用したい場合は、新たに導入された :prototype 属性 (attribute) を使用することができます。

sub add ($$) { # 必ず2引数を強制するプロトタイプ宣言
    my $left  = shift;
    my $right = shift;
    return $left + $right;
}

というプロトタイプ宣言をサブルーチンシグネチャと混用したければ

use feature qw(signatures say);
no warnings "experimental::signatures";

# 5.20 および 5.28
sub add :prototype($$) ($left, $right) {
    return $left + $right;
}

# 5.22、5.24、5.26
sub add ($left, $right) :prototype($$) {
    return $left + $right;
}

と書くと良いでしょう。

プロトタイプ宣言とシグネチャの順序が、Perlのバージョンに応じて変わっています(Perl5.28 での変更は :lvalue の場合の問題回避とのこと)。それほど多くはないと思いますが、両者を混ぜて使う場合は注意しましょう。

詳細は perlsub を参照下さい。

refaliasing - リファレンスによる別名変数定義

refaliasing は別名変数を定義する方法を提供するものです。

use feature qw(refaliasing say);

my ($x, $y);
\$x = \$y; # refaliasing

$y = "hello";
say "x is $x"; # hello
$x = "hi";
say "y is $y"; # hi

リファレンスによる別名を \$x = \$y とした後は、$x$y は全く同じ値を持つことになり、かつ $x の変更が $y にも「同期」され、その逆も同様となります(つまり、 \$x = \$y\$y = \$x は意味的に同じです)。

今までの Perl では、リファレンスを取得する \$x といった構文を代入の左辺に持ってくることはできなかったのですが、それを可能にするのが refaliasing です。

ただし Perl 5.28 現在、そのままでは

Aliasing via reference is experimental

といった警告が出てきてしまいます。理解して使っているのでこれを抑止したいという場合には

no warnings "experimental::refaliasing";

と書きます。

ちなみに、refaliasing はスカラーだけでなく、配列やハッシュでも同様に機能します。

use feature qw(refaliasing);

my $hashref = {
   name => "Bull",
   type => "Dog",
}
my %x;
\%x = $hashref; # refaliasing

refaliasing を使うと、サブルーチン・メソッドの別名定義が明快になります。

Perl5 にてサブルーチン・メソッドの別名定義をする場合、以下のように別名としたい名前のグロブ変数にサブルーチンリファレンスを代入していました。

sub search {
    ...
}
# find は search の別名
*find = \&search;

グロブは Perl4 時代からあるリファレンスの始祖のような存在ですが、それゆえマジカルで古い書き方のような印象を覚えます。もっとも、モダンな Perl5 コーディングにおいて、グロブはこのようないくつかの用例のみがあるイディオムと扱えば良いものの、これも refaliasing でより明快な書き方ができます。

use feature qw(refaliasing);
sub search {
    ...
}
# find は search の別名
\&find = \&search;

スカラー・配列・ハッシュといったデータ型は my $find と宣言していない状況で \$find とリファレンスを書くと strict によって例外となってしまいますが、サブルーチン find (または &find)が定義されていない状態で \&find と書いても問題ありません。

もっとも、my $cb = \&find; の後で $cb->() と呼び出したときに

Undefined subroutine &main::find called

と警告を受けることになるでしょう。

なお、サブルーチンの別名を定義しようとして以下のようにすると表面的には要望を実現できますが、ある種の状況(caller 等で呼び出しを詳細に観察している場合)で混乱することがあるかもしれません。またパフォーマンスは上記による別名作成よりも少し悪いでしょう。

sub find {
    search(@_);
}

なお、下記であれば上記より多少問題が緩和されます。

sub find {
    goto &search;
}

詳しくは gotocaller の解説を参照下さい。

少し話が飛んでしまいましたが、refaliasing の話に戻りましょう。

別名変数とは、もともとは for で指定される受け渡し変数や、 map が伴うブロック中の $_ のことを言いました。

my @numbers = (1...5);

for my $number (@numbers) {
    # 二乗した値を表示したいので $number をまず二乗する
    $number **= 2;
    print "number is $number\n";
}

# なぜか @numbers の配列の内容が書き換わっている
print join ", ", @numbers; # 1, 4, 9, 16, 25

上記では、一時的に for のスコープ中の一回のループでのみ有効な $number を変更しただけなのに、なぜか配列 @numbers 自体が書き換わっています。

実は、上記のように for $number (@numbers) といった配列を丸括弧内に置く書き方をすると、例えば初回ループでの $number$numbers[0] と真に同一の変数となるのです。つまり $number を破壊すると $numbers[0] も破壊することになります。

このような挙動の変数は formap で有名です。

上記を意図通り書くとすれば、以下のように書きます。

my @numbers = (1...5);

for my $number (@numbers) {
    print "number is " . ($number ** 2) . "\n";
}

print join ", ", @numbers; # 1, 2, 3, 4, 5

「二乗 ** ならそんな書き方しないでしょう」という方も、破壊が基本の $string =~ s/// 構文等で上記のような失敗を踏んでしまうことは十分考えられます(そして Perl5.14 以降で使えるようになった非破壊置換 s///r も調べてみて下さい)。

なぜ上記のような動作になっているのか。私は「変数の内容をコピーするコストを抑えるため」と理解しています。

なお、上記の for の別名変数の特性を逆に利用する書き方もあります。

# 配列の中のキーワード全てを最初に小文字に変換しておく
for (@keywrods) {
    $_ = lc $_;
}

# 一時的に長い変数名を反復して書きたくない
for ($very_very_long_name_variable) {
    s/foo/BAR/;
    s/buz/QUUX/;
    $_ = quotemeta($_);
}
# 文全体の文字が少なければ、後置 for で `s///, s///, s/// for $string` と書いてもよい

横道にそれてしまいましたが、別名変数であることはチームメンバーに対して混乱を生む可能性もあるので、for 等の別名変数を意図した使用や refaliasing の使用に際しては、その妥当性を十分検討してチーム全体の合意を取る必要があるでしょう。

bitwise - ビット演算子を数値専用と文字列専用に分ける

Perl にはビットに対する AND OR XOR といった演算を行うビット演算子があります。

  • ビットごとの論理積 &
  • ビットごとの論理和 |
  • ビットごとの排他的論理和 ^
use feature qw(say);

say  105  |  150;  # 255
say "105" | "150"; # 155

ビット演算子は、両辺が数値か文字列かで意味が変わってきます

  • 右辺か左辺どちらかが数値であれば、数値のビット演算
  • 右辺と右辺のどちらも文字列であれば、各桁の文字についてビット演算したもの

もし、外部から受け取ったスカラー変数をビット演算で評価する場合、それが数値なのか、(数値に見せかけた)文字列なのかを厳密に扱いたい場合があります。

今までの Perl でも、明示的な数値化 0+$x や文字列化 "$x" を使うことで回避していました。

use feature qw(say);

sub bit_add {
   my ($left, $right) = @_;
   # 引数は必ず数値
   return 0+$left | 0+$right;
}

# 外部から <STDIN> などで読み込んだデータは数字であっても、
# データとしては文字列になっている
say bit_add("150", "105"); # 255

しかし、 0+$x"$x" は少々トリッキーな書き方ということもあり、これを解決するための bitwise feature が生まれました。

use feature qw(bitwise); をすると

  • ビット演算子 | & ^ は必ず両辺を数値として扱う
  • 新たに |. &. ^. というビット演算子が導入され、それらは必ず両辺を文字列として扱う

という変更が発生します。

use feature qw(say);

sub bit_add {
   my ($left, $right) = @_;
   # 引数は必ず数値
   use feature qw(bitwise); # このスコープでのみ `|` の挙動を変えたい場合はここで宣言するとよい
   return $left | $right;
}

say bit_add("150", "105"); # 255
say "150" | "105";         # 155

ただし Perl 5.26 までは、use feature qw(bitwise); 時にビット演算を行うと

The bitwise feature is experimental

といった警告が出てきてしまいます。理解して使っているのでこれを抑止したいという場合には

no warnings "experimental::bitwise";

と書きます。

Perl 5.28 より、警告が出なくなりました。

declared_refs - リファレンスの直接宣言

declared_refs を使うと、リファレンス自体を my 宣言することができます。

use feature qw(declared_refs);
my \$x; # \$x を宣言する、つまり $x も同時に宣言する

これの何が嬉しいのかというと、refaliasing との相性が良いことでしょう。

refaliasing では、リファレンスの直接定義ができると書きました。

use feature qw(refaliasing say);

my ($x, $y);
\$x = \$y; # refaliasing

$y = "hello";
say "x is $x"; # hello
$x = "hi";
say "y is $y"; # hi

この場合、変数宣言自体を行った後で代入 \$x = \$y を行っていることがわかります。refaliasing を多用する場合、これが手間だという人もいるでしょう。

この手間を省き、変数のリファレンスを直接宣言できるようにするのが declared_refs です。

use feature qw(declared_refs refaliasing say);

my \$x = my \$y; # declared_refs && refaliasing

$y = "hello"; # $x に初めて値を入れる
say "x is $x"; # hello
$x = "hi";
say "y is $y"; # hi

ただし Perl 5.28 現在、そのままでは

Declaring references is experimental

といった警告が出てきてしまいます。理解して使っているのでこれを抑止したいという場合には

no warnings "experimental::declared_refs";

と書きます。

もっとも、 my \$x; は今までできなかったわけですが、\my $x; という書き方はできました(バッククォートの位置に注目)。my は宣言に成功したら式全体は宣言した空の変数そのものとして使うことができるので、以下のような書き方で上記と同様なことができます。

# declared_refs がなくても以下はできる
\my $x = \my $y;

\my $x ができれば declared_refs 要らないのでは?」という疑問も浮かびますが、そもそも \my $x という表記が初見殺しであること、また丸かっこでまとめて my 宣言する場合に \my ($x, $y, $z) の式全体の評価値が (\$x, \$y, \$z) となることが都合悪い場合もあることも declared_refs の後押しになったのではと感じています。詳細は perlref - Declaring a Reference to a Variable を参照下さい。

refaliasing にまつわる警告は refaliasing の節を参照下さい。