Featured image of post コードカーペンター【Parameterize Constructor】「柱ごと、外から渡すんですか」〜中で作っていた相手を、渡しても渡さなくても建つ形にする〜

コードカーペンター【Parameterize Constructor】「柱ごと、外から渡すんですか」〜中で作っていた相手を、渡しても渡さなくても建つ形にする〜

二階の勘定場の記帳を検めたいのに、組み立てた途端に本物の大福帳が開いてしまう。中で作られた相手には名前が無く、local も届かない――コンストラクタのパラメータ化(Parameterize Constructor)で、渡しても渡さなくても建つ形にします。

第1幕: 検分 ── 二階へ上がる

二階へ上がる階段は、段ごとに鳴る音の高さが違う。下から三段目は低く、七段目は乾いた高い音がして、最後の一段だけはほとんど鳴らない。三十年も上り下りしていると、目をつぶっていても、今どこまで上がったかが足の裏で分かる。

午後だった。表の通りの声は一階の土間で止まって、二階までは上がってこない。格子窓から斜めに入った光が、畳の縁に細長い形を落としていた。

二階の奥は勘定場になっている。店主が月末に帳尻を合わせる小さな座敷で、古い文机の横に端末が一台置いてある。大福帳――売り買いを日ごとに書き足していく帳面――は、今はもう紙ではなく、その端末の中のファイルに一行ずつ増えていく。ふだん二階に上がるのは、私と店主くらいのものだ。

「店主から、頼まれごとがありまして」

階段を上がりきったところで、私は振り返って言った。後ろからクロベさんとナギさんが、道具箱を提げて上がってくる。

「二階の記帳の書き方を、一度検めてほしい、と。戻り金のときは金額の頭に三角を付ける決まりなんですが、先月、それが一件だけ違って見えた気がするそうで。気がする、というだけで、どの日のどの行かまでは――」

言いながら勘定場へ目を向けると、クロベさんはもう文机の前に膝をついて、端末の画面を見ていた。いつ私を追い越したのか分からなかった。階段の途中から、開けたままの襖越しに画面が見えていたのだと、あとになって気づいた。

画面には、二階の記帳を受け持つ仕組みのソースが開かれていた。

ナギさんは道具箱を下ろすと、勘定場の手前の床板に手をかけた。

「一枚、上げてもいいですか」

「どうぞ」

答えるのに迷わなかった。二階の床板を人に上げさせたことは、これまで一度も無い。ナギさんがバールの先を差し込むと、古い釘が短く鳴いて板が浮いた。床下の暗がりから、何年分かの埃の匂いが立ちのぼる。その下に、太い梁が一本、横たわっていた。

ナギさんが拳の背で梁を叩いた。詰まった、重い音がした。

「ここは、柱にしっかり噛んでいます。組み上げたときのまま、どこも浮いていません」

クロベさんは画面に目を置いたまま、短くうなずいた。それから、その一部を目で追いながら、声に出して読みはじめた。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package Nikai::Daifuku;

use strict;
use warnings;

sub new {
    my ($class, %args) = @_;
    open my $fh, '>>', $args{path} or die "大福帳を開けません: $args{path} ($!)";
    return bless { fh => $fh }, $class;
}

sub post {
    my ($self, $date, $item, $amount) = @_;
    $item =~ s/\t/ /g;
    my $abs  = abs($amount);
    my $text = scalar reverse join ',', unpack '(A3)*', scalar reverse $abs;
    $text = "△$text" if $amount < 0;
    my $line = "$date\t$item\t$text\n";
    print { $self->{fh} } $line;
    return $line;
}

1;

「newで組み立てて、postで一行書く。それだけの仕組みです」

クロベさんは、postのほうから先に説明した。日付と品目と金額を受け取り、タブで区切った一行にして書き足す。金額は三桁ごとにカンマで区切る。数字をいったん逆さに並べ、三文字ずつに切ってカンマで繋ぎ、もう一度逆さに戻す――そういうやり方で区切っているのだという。負の金額なら、頭に三角を付けて、数字のほうは絶対値で書く。品目の中にタブが紛れ込んでいたら、空白一つに置き換える。

「このタブの置き換えは、何のためなんですか」

「大福帳は、タブで欄を分けています。品目の中にタブが入ったまま書くと、一行の欄の数が狂って、あとで読むときに品目と金額がずれます。この一行があるから、今まで壊れた行が大福帳に残らずに済んでいる」

それから、クロベさんはnewのほうへ目を移した。

「こっちが、今日の本題です」

open my $fh, '>>', $args{path}という一行だけは、クロベさんの読む速さが落ちた。

「openはファイルを開く命令です。'>>'は、追記で開く、という指定です。ファイルが無ければ作り、あれば末尾から書き足す。前の日の記帳を上書きせずに、毎日少しずつ伸ばしていけるのは、この一行のおかげです」

開いたファイルを扱う手――ファイルハンドル――は、my $fhという入れ物に収められ、そのまま組み立てたものの中に仕舞い込まれる。以後、postはその手を使って書き込む。

「つまり、これは組み立てた途端に、本物の大福帳を開きます」

「検めをしたら、本物の大福帳に一行入ってしまう、ということですか」

私が訊くと、クロベさんは一言だけ答えた。

「入ります」

床下から、ナギさんが梁を叩く音がもう一度した。

第2幕: 手が入らない ── 名前が無い

ナギさんが床板を脇に立てかけ、手の埃を払ってクロベさんの横へ来た。画面を覗き込み、それから顔を上げた。

「じゃあ、この前みたいに――」

「localは届きません」

クロベさんの声が、ナギさんの言葉の終わりに重なった。

「この前の、子のクラスで上書きする手も、ここでは使えません」

ナギさんは口を開いたまま、少しのあいだ動かなかった。それから、「……はい」とだけ言った。膝の上に置いた手が、そのまま止まっていた。何か二つ、言うつもりだったのだと思う。その二つとも、先に言われてしまったのだ。

クロベさんは、画面のほうを向いたまま、一つずつ話しはじめた。

「まず、localです。localは、名前の付いた入れ物の中身を、しばらくのあいだだけ別のものにすり替えて、終わったら元に戻す仕組みでした。店の間の値札のときに使った手です」

私は、あのときのことを思い出していた。税率を返す仕組みの名前を、検めのあいだだけ別のものに差し替えた。差し替えたのは、パッケージに登録された名前――誰からでもShop::Tax::rateのように呼べる名前――だった。

「ところが、このmy $fhは、そういう名前の付いた入れ物ではありません。myで作った入れ物は、それを書いた場所の中――ここではnewの中――だけにあって、パッケージの名前の一覧には載りません。newの外から見ると、この入れ物には、名前が無い」

「名前が無い」

私が繰り返すと、クロベさんは顎を引いた。

「名前が無いものは、localで指しようがありません」

ナギさんが、ゆっくりと顔を上げた。

「パッケージの名前を付けて書いたら、どうなりますか。$Nikai::Daifuku::fhみたいに」

言いかけて飲み込んだものの一つが、それだったのだろう。クロベさんは、それを待っていたように答えた。

「書けます。Perlはそれを黙って通します。そして、本物の大福帳に書きます」

クロベさんは、端末の脇に短いコードを打ってみせた。

1
2
3
4
open my $mem, '>>', \my $buf or die $!;
local $Nikai::Daifuku::fh = $mem;
my $d = Nikai::Daifuku->new(path => $path);
$d->post('2026-09-30', '畳表', 12000);

「$Nikai::Daifuku::fhというのは、Nikai::Daifukuというパッケージの$fhという名前の入れ物です。そういう入れ物は、書けばその場でできてしまう。できたばかりの空の入れ物を、localは言われたとおりすり替えます。でも、newの中のmy $fhとは、まったく別のものです。だから、すり替えても何も起きない」

「何も起きない、というのは……」

「エラーにはなりません。used only once: possible typo――この名前は一度しか使われていないが、打ち間違いではないか――という警告が一本出るだけです。同じ名前をどこかでもう一度書けば、その警告さえ消えます。検めのほうは本物の大福帳に一行書いて、何事も無かったように終わる」

クロベさんは、そこで一度言葉を切った。

「一番怖いのは、これです。止まらずに、間違ったほうへ書く」

私は、店主の顔を思い浮かべた。月末に大福帳を開いて、見覚えの無い畳表の売り上げが一行入っているのを見つける。誰が書いたのか分からない一行を、店主はきっと一晩かけて探すだろう。

「井戸のときの手のほうは、どうですか」

ナギさんが訊いた。これが、もう一つだったのだと思う。

井戸の一件のとき、クロベさんたちは、外へ問い合わせに行く呼び出しを、その仕組み自身のメソッドとして切り出した。検めのときだけ、そのメソッドを上書きした子のクラス――サブクラス――を使う。そうして、外へ出る縄だけを、検め用の縄に替えたのだった。桶をつけない縄――あのときクロベさんは、そう呼んでいた。

「あれは、上書きできるメソッドがあって、初めて効く手です」

クロベさんは、newの中のopenを目で指した。

「openは、Perlに組み込みの命令です。この仕組みのメソッドではありません。子のクラスでpostを上書きしても、組み立てるときには親のnewが動いて、openはそのまま走ります。上書きできる継ぎ目が、ここには無いんです」

「組み込みの命令そのものを、差し替える手は無いんですか」

ナギさんが食い下がった。

「あるにはあります。CORE::GLOBAL::openという名前に仕込めば、openを横取りできる。ただ、呼ぶ側のコードが読み込まれる前に仕込まないと効きませんし、効いたら効いたで、その間に走るすべてのopenを巻き込みます。二階の大福帳だけを狙って替える、ということができません」

「newごと上書きしたら」

「できます。ただ、そのためにはnewの中身をまるごと子のクラスへ書き写すことになる。そうすると、検めは本物のnewを一度も通らなくなります。本物の組み立て方が変わっても、検めは気づかない。何を検めているのか分からなくなります」

ナギさんが、自分の手を見下ろした。何かを書く前の手の形のまま、指が止まっていた。

私は、ナギさんが上げた床板の下を覗いた。梁は、組み上げたときのまま、柱に深く噛んでいた。どこにも隙間は無く、仮の支えを横から差し込めるような余地は、見当たらなかった。

「一つだけ、書いてみてください」

クロベさんが、ナギさんに言った。

「証文代わりです。$fhに、そのままlocalを掛けてください」

ナギさんは検めのファイルを開き、一行だけ書き足した。

1
2
open my $mem, '>>', \my $buf or die $!;
local $fh = $mem;

走らせると、画面に二行の文字が出た。

1
2
Global symbol "$fh" requires explicit package name (did you forget to declare "my $fh"?) at t/red/3_local_lexical.pl line 6.
Execution of t/red/3_local_lexical.pl aborted due to compilation errors.

$fhという名の入れ物は、どこにも無い。パッケージの名前を付けて書け。――検めは、一行も動かずに止まっていた。

誰も、何も言わなかった。

第3幕: 手立て ── 柱を外から持ち込める仕口

最初に口を開いたのは、クロベさんだった。

「親切に、my $fhを宣言し忘れていないか、と訊いてくれていますが」

画面の末尾の括弧を、クロベさんは目で示した。

「言われたとおり、ここでmy $fhと書いても、それは検めのファイルの中に新しくできる、別の入れ物です。大福帳のnewの中の$fhには、どうやっても届きません」

ナギさんが、書き足した一行を消した。

「では、どうするんですか」

私が訊くと、クロベさんは、画面をnewのほうへ戻した。

「中で作っているから、外から届かない。だったら、外から渡せるようにします」

クロベさんは、手を膝に置いて、正面から私のほうを見た。

「コンストラクタのパラメータ化――Parameterize Constructor――という技法です。コンストラクタ、つまりこのnewのような組み立て役の中で作っていた相手を、引数で受け取れるようにする。受け取らなかったときは、今までどおり自分で作る」

「受け取らなかったときは、今までどおり」

「そこが肝心です」

クロベさんは、postのほうを目で示した。

「postは、受け取った手にprintするだけです。だから渡すものは、書き込めるファイルハンドルでありさえすれば、何でも構いません。渡す側が請け合うのは、その一点だけです」

クロベさんはうなずいた。

「この技法を書いた人も、そこを大事にしています。引数を一つ足すと、今この仕組みを呼んでいる所が全部、新しい引数を渡さなくてはならなくなる――そう思い込んで、みんなこの手を思いつかないのだ、と。実際には、元の呼び方を残したままにしておける。書いた人が例に使っていた言語では、組み立て役を二つ並べて、引数の無いほうから、引数のあるほうへ、いつもの相手を作って渡すように書きます」

「Perlでも、二つ並べるんですか」

「Perlのnewは、名前付きの引数を一つの束で受け取ります。二つ並べる代わりに、一つのnewの中で分かれ道を作れば、同じことになります」

クロベさんがナギさんのほうを見た。ナギさんは、もう画面の前に座り直していた。

「ledgerという名前で、渡せるようにしてください。渡されなかったら、今までどおりpathを開く」

ナギさんが打ちはじめた。my $fh = $args{ledger} ||まで書いて、手が止まった。

「どっちでも動きますよね。||でも、//でも」

ナギさんは、画面を見たまま訊いた。クロベさんが答えた。

「今日のところは、どちらでも動きます。ただ、//にしてください」

「違いは何ですか」

私も訊いた。クロベさんは、画面の二つの記号を目で比べてから話した。

「||は、左側が偽なら右側を使います。Perlでは、未定義の値――undef――だけでなく、0や空の文字列も偽です。//のほうは、左側が未定義のときだけ右側を使います。値が渡されていれば、それが0でも空でも、そのまま使う」

「ファイルハンドルは、0になることはありませんよね」

ナギさんが言った。

「なりません。開いたファイルハンドルは、いつも真です。だから今日は||でも同じに動く。それでも//にするのは、渡されたものを、偽に見えるからといって勝手に捨てない、という書き方の癖を揃えておくためです。癖が揃っていれば、次に誰かが数を渡す引数を足したときに、0を黙って捨てずに済みます」

ナギさんは||を消して、//と打ち直した。//はPerl 5.10から入った記号で、今のPerlなら何も気にせず使えるのだと、クロベさんは付け加えた。

書き上がったnewは、こうなった。

1
2
3
4
5
6
7
8
sub new {
    my ($class, %args) = @_;
    my $fh = $args{ledger} // do {
        open my $real, '>>', $args{path} or die "大福帳を開けません: $args{path} ($!)";
        $real;
    };
    return bless { fh => $fh }, $class;
}

変わったのはnewの中の、大福帳を開く所だけで、postには一文字も触れていない。

「do { ... }は、中の何行かを順に実行して、最後の行の値をその場の値にする書き方です。ここでは、開いたファイルハンドル$realが、その値になります」

クロベさんは、//の右側を目で示した。

「大事なのは、//の右側は、左側が未定義のときにしか実行されない、ということです。ledgerを渡せば、doの中身は動かない。openが走らない。本物の大福帳は、開かれもしません」

私は、床下の梁のほうを見た。

「梁を組むときに、柱を外から持ち込めるように、仕口を開けておくようなものです」

クロベさんが言った。

「持ち込めば、その柱で組む。持ち込まなければ、いつもの柱で組みます」

「柱ごと、外から渡すんですか」

思わず、そう訊いていた。クロベさんは、少しだけ口元を緩めた。

「渡したければ。渡さなければ、何も変わりません」

組み立てるときに何を使うかを、組み立て役の中で決めてしまうのではなく、組み立てを頼む側が選べるようにする。これまでnewの中に固く噛んでいた本物の大福帳との結びつきが、呼ぶ側の手元へ移ったのだと、私は理解した。

「では、今この仕組みを使っている所は、何か変えないといけないんですか」

引き受ける側として、それを一番に確かめておきたかった。クロベさんは、店主が月末に使っている締めの手順を開いた。

1
2
3
4
5
6
7
8
use strict;
use warnings;
use lib 'lib';
use Nikai::Daifuku;

my $DAIFUKU_PATH = shift // 'daifuku.txt';
my $daifuku = Nikai::Daifuku->new(path => $DAIFUKU_PATH);
$daifuku->post('2026-09-30', '畳表', 12000);

「Nikai::Daifuku->new(path => $DAIFUKU_PATH)。今日の手を入れる前も、入れた後も、この一行は一文字も変わりません。ledgerを渡していないので、newは今までどおりpathを開きます」

「じゃあ、検め用の何かを渡すのは、誰なんですか」

「検めのコードです」

クロベさんは、はっきり言った。

「検め用の帳面を作ってledgerで渡すのは、検めのコード自身です。検めのときだけ、検めのコードが組み立て役に柱を手渡している。組み立てているのは、どちらの場合も同じnewです」

私は野帳に、組み立ての前と後で、誰が大福帳を決めているのかを並べて描いてみた。

手を入れる前と後の対比図。前は店主の締めの手順も検めのコードもpathだけで呼び、newが本物の大福帳を開く。後はledgerが渡されたかで分岐し、渡されればopenは走らず検め用の帳面を使い、postは変えずに記帳する

描いてみると、変わったのはnewの入口の一か所だけで、店主の手順からpostまでの線は前と同じ場所を通っていた。

「検め用の帳面、というのは」

「これです」

クロベさんは、さっき一度見たのと同じ一行を指した。

1
open my $mem, '>>', \my $buf or die $!;

「\my $bufは、my $bufという変数をその場で作って、\でその参照を渡す書き方です。openは、ファイルの名前の代わりに、こうして変数への参照を渡すと、ファイルではなくその変数に向かって開きます。書き込んだ中身は、ファイルではなく$bufという変数に溜まる。手元で読める、紙一枚の帳面のようなものです。中身を確かめるのは、closeで閉じてからにします。閉じる前だと、書いたものがまだ手前で溜まっていて、変数に届いていないことがあるので」

ナギさんが、何か言いたそうに私のほうを見て、それからクロベさんに訊いた。

「桶をつけない縄とは、何が違うんでしょう。どっちも、検めのときだけ別のものを使う、ですよね」

「あのときは、仕組みの中に継ぎ目になるメソッドを作って、それを子のクラスで上書きしました。今日は、継ぎ目のメソッドも、子のクラスも要りません」

ナギさんは、画面のnewをしばらく見ていた。

「……今日のほうが、組み立てるところが、よく見えます」

第4幕: 検め ── 仮の部材を入れ替える手

検めは三つに分かれていた。

一つ目は、今までの呼び方で組み立てたとき、手を入れる前と後のnewがまったく同じ大福帳を書くことの確かめだった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
my @inputs = (
    ['2026-09-30', '畳表',       12000],
    ['2026-09-30', '返品',       -1200],
    ['2026-09-30', '据え置き',       0],
    ['2026-09-30', '釘',           980],
    ['2026-09-30', '梁',       1234567],
    ['2026-09-30', "丸\t太",      500],
    ['2026-09-30', '檜の板',     -999],
);

my $dir = tempdir(CLEANUP => 1);
my (@ret_b, @ret_a);
{
    my $b = Nikai::Daifuku->new(path => "$dir/before.txt");
    my $a = Nikai::DaifukuAfter->new(path => "$dir/after.txt");
    for my $in (@inputs) {
        push @ret_b, $b->post(@$in);
        push @ret_a, $a->post(@$in);
    }
}

is_deeply(\@ret_a, \@ret_b, '全入力で post の戻り値が Before と After で一致する');
is(slurp("$dir/after.txt"), slurp("$dir/before.txt"), '全入力で書き込まれたファイルの中身が一致する');

検めのためだけに、手を入れる前のnewをNikai::Daifuku、手を入れた後をNikai::DaifukuAfterという別の名前で並べてある。ファイルを写してパッケージの名前だけを替え、postは一字も違えずにそのまま、違うのはnewだけだ。検めが済めば、手を入れた後の形を本体へ戻す。どちらもpathだけを渡す、今までどおりの呼び方で組み立てる。正の金額、負の金額、ゼロ、カンマの付かない三桁の数、七桁の数、タブの紛れ込んだ品目。並べた入力を両方に同じ順で書かせ、書き込まれた二つのファイルの中身を、先頭から末尾まで比べる。tempdirは、検めが終われば消える一時的な置き場所を用意してくれる道具で、本物の大福帳には近づかない。

「今までの呼び方で組んだら、前と同じ大福帳が、同じように伸びます」

クロベさんはそれだけ言った。

二つ目は、検め用の帳面を渡したときの確かめだった。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
subtest 'インメモリの帳面を渡すと、書式どおりの行が帳面に入る' => sub {
    my $dir = tempdir(CLEANUP => 1);
    my $path = "$dir/daifuku.txt";
    open my $mem, '>>', \my $buf or die $!;
    my $d = Nikai::DaifukuAfter->new(path => $path, ledger => $mem);
    $d->post('2026-09-30', '畳表', 12000);
    $d->post('2026-09-30', '返品', -1200);
    close $mem;
    is($buf, "2026-09-30\t畳表\t12,000\n2026-09-30\t返品\t△1,200\n", '帳面に期待どおりの2行が入る');
    ok(!-e $path, '本物の大福帳のパスにファイルは作られない');
};

帳面に入った二行が、決まりどおりの形をしていること。三桁区切りのカンマ、戻り金の三角。そして、pathに大福帳の置き場所を渡しているのに、そこにファイルが作られていないこと。ledgerを渡したので、openは走らなかったのだ。

三つ目は、ledgerを渡さないとき――正確には、渡しても中身が未定義のとき――に、今までどおりpathのファイルへ書き込まれることの確かめだった。//は未定義の値を「渡されていない」と同じに扱うので、そこも押さえておくのだという。

走らせると、どれも通った。

1
2
3
4
t/daifuku_equivalence.t .. ok
t/daifuku_ledger.t ....... ok
All tests successful.
Result: PASS

画面を見ていて、一つ気になることがあった。

「localのときは、検めが終われば元に戻る仕組みがあったから、安心して使えました。今日のは、何を頼りに安心していいんでしょう。戻し忘れたら、誰が気づくんですか」

呼ぶ側が選べる形になったことは、分かったつもりでいた。けれど、選んだあとの後始末を誰がするのかは、まだ聞いていなかった。

クロベさんは、答えなかった。代わりに、画面の検めのコードの、ledger => $memと書いてある一行を目で示した。

私はその一行を読んだ。検めの中で、Nikai::DaifukuAfter->newを一つ組み立てている。その一つにだけ、検め用の帳面を渡している。

どこかの名前を、すり替えているわけではなかった。店主の締めの手順が呼ぶnewも、二階の勘定場の大福帳も、どこも何も替わっていない。検めの中で組み立てた一つが、検めの中で使われて、検めが終わるとそのまま無くなる。

「戻すものが、無いんですね」

口にしてから、自分で少し驚いた。クロベさんは、ようやくうなずいた。

「はい。どこも替えていないので、戻し忘れようがありません」

私は、端末のほうへ手を伸ばしていた。

誰かに促されたわけではない。キーボードの上で少し迷ってから、検めのコードのopen my $memの行を真似て、その下にもう一行、open my $mem2, '>>', \my $buf2 or die $!;と書いた。そして、ledger => $memの$memを、$mem2に書き換えた。閉じる行のclose $memもclose $mem2に、帳面の中身を受ける$bufも$buf2に直した。キーの一つ一つを確かめながら打ったので、ずいぶん時間がかかった。

走らせると、通った。

横で、ナギさんが膝の上の手をほどくのが見えた。

「帳面を替えても、組み立て方も、postも、何も変わらずに通る」

クロベさんが言った。

「検め用の部材を入れ替えるのは、渡す一行を書き換えるだけです。今日の技法で開けたのは、そのための差し込み口です」

それから、クロベさんは、保証することと、しないことを区切って話した。

「今日の手で言えるのは、記帳の書き方を、本物の大福帳に触れずに検められるようになった、ということです。今この仕組みを呼んでいる所は、何も変えなくていい。手を入れる前と後で、今までの呼び方なら、どんな金額でも同じ行が同じファイルに書かれる」

「言えないのは」

「本物の大福帳が開けないとき――置き場所が無い、書き込みが許されていない、置いてある所がいっぱいになった――そういうときの振る舞いは、検めていません。今までどおりの経路は、一時的な置き場所で一度通しただけです。それに、これは一度動かしたときの話です。毎日この勘定場で使い続けていて、何が起きても大丈夫だ、とまでは言えません」

クロベさんは、床下の梁のほうへ一度目をやった。

「もう一つ。渡せるようにしても、この仕組みは、本物の大福帳の開き方をまだ自分の中に抱えています。渡されなかったときのために、です。渡すものが二つ、三つと増えていけば、newは膨らみます。渡されなかったら自分で作る、という形は、今呼んでいる所を守るための既定であって、これで仕上がりというわけではありません」

「渡されなかったら自分で作る、というのは、よくないやり方なんですか」

「よそでは、嫌われることもあります。組み立てを自動でやってくれる道具を使う言葉だと、その道具が、引数の無い呼び方のほうを選んでしまって、せっかく用意した検め用のものが渡らない、ということが起きる。この店のPerlには、そういう道具は入っていませんから、その心配は今はありません。ただ、自分で作る分だけ、本物とのつながりはまだ中に残っている――それは覚えておいてください」

私は、野帳を開く前に、一度、端末に向き直った。

検めの中ではなく、店主がいつも開いている本物の大福帳を開いた。一番下までずっと送っていく。最後の行は、昨日の夕方、店主が書き足した釘の仕入れのままだった。畳表の一万二千も、三角の付いた返品も、どこにも入っていなかった。

それを確かめてから、私は野帳に書いた。

「仮の部材を、自分で入れ替えられる」

書いたあとで、野帳の余白に、さっき自分で打った一行を小さく書き写した。ledger => $mem2。明日の朝には、たぶんもう、何も見ずに打てる。

振り返ると、ナギさんが床板を元に戻していた。木槌で二度、軽く叩く。板は元の場所に収まって、梁はもう見えなくなった。格子窓の光は、さっきより少しだけ長く伸びて、畳の縁を越えていた。


普請控

  • 見立て: 二階の勘定場で記帳を受け持つNikai::Daifukuは、組み立てた途端に本物の大福帳を開いていた。開いたファイルハンドルはnewの中のmy $fhに収まっていて、外からは名前が無い。localは届かず、パッケージ名を付けて書けば黙って空振りして本物に書き、子のクラスで上書きしようにもopenには上書きできる継ぎ目が無かった
  • 手を入れた所: コンストラクタのパラメータ化(Parameterize Constructor)を使った。newに省略できるledgerを足し、渡されなければ今までどおり自分で大福帳を開くように、$args{ledger} // do { open ... }と書いた。検めでは、変数に向かって開いた検め用の帳面を渡す
  • 触っていない所: postの中身は一文字も変えていない。タブで欄を分ける形、三桁区切り、戻り金の三角という記帳の決まりもそのまま。店主の締めの手順が呼ぶNikai::Daifuku->new(path => ...)という呼び方も、大福帳ファイルの置き場所も、末尾から書き足していく開き方も変えていない
  • 次の工程へ送ること: 店主が気にしていた、先月一件だけ三角の書き方が違って見えたという件は、今日は探していない。本物に触れずに検める手立てができたので、次はそれを使って先月分を確かめる。本物の大福帳が開けないときの振る舞いも、まだ検めていない
  • 私が引き受けたこと: 検め用の帳面を、今日は自分の手で別のものに差し替えて通した。仮の部材を入れ替えるのは渡す一行を書き換えるだけで、どこも替えていないから戻し忘れも起きない。だから、これからは検め用の部材の入れ替えを、棟梁を待たずに自分でやる
comments powered by Disqus
システム開発・AIワークフローのご相談は Meetsource へ
Hugo で構築されています。
テーマ Stack は Jimmy によって設計されています。