これはPerl Advent Calendar 2025の八日目ぐらいの記事です。 たまたまカレンダーを見たら枠が空いていたので気まぐれの思いつきで書くことにしました。 師走八日の夜十時*1の時点で今日の枠が埋まってないので飛び入り参加です。
今年は(も)YAPCへ行けなくてPerl成分が全くない一年ってのも無粋やし何か書くかと思い起こせば、昨年末から別の言語ばっかり書いててPerlはあんまり書いてなくて何もない?と思いつつも、Perlから少し離れたことで起きたことについて書きます。
年末からGoを書くことが多くなってるのを「アカンで?バランスやで?」と諌めるかのごとくPerlのタスクが何個か降ってきたんやけどGitHubではほぼ同じ色やし文字列処理とデプロイが楽でコンパイルもできるPerlって使い方をしてるし実質的に同じ言語みたいなモンやろ、たぶん。 pic.twitter.com/3yDMld5vHw
— ネコ物質¹³⁰³¹ (@azumakuniyuki) August 1, 2025
掲題はちょっと大げさ・誇張表現でして、実際に読めないことはないのですが、unlessで書いてる条件を理解するのに時間がかかるようになりました。
前提
わりと前からメール関係のライブラリをPerlとRubyで同じものとして実装したのをOSSとして公開してて、
今年の二月にGoで書いた同じものをリリースしました。
で、PerlとRubyには存在するunlessがGoには無いので、全てifで書いたわけですが、まだリリースして時間が経ってなく僕がGoに慣れてない故にコードが幼いこともあり、
効率を上げたりいろいろ細いリファクタリングでGoを触る時間が多くなりました。
原本
同じものを三言語で実装しているのですが、Goで書いたやつ が一番カッチリしてて僅かですが精度も高いので、また、最初にGoで書いて、フワッと書いても大丈夫なPerlに移植することで、例外的な値の入力やら考慮漏れも防げるので、 Go版が原本でありバグ修正や新しい機能の実装は先ずGoで書いて、動作を確認したらPerlとRubyにも移植するって開発方針にしています。
unlessが読めない
そこで発覚したのがunlessが読めなくなってるです。
// Go if neko != "nyaan" { return false }
って書いているのをPerlで書くとき、周辺の条件文がunlessで書いているから合わせようと
# Perl(1) return 0 unless $neko eq "nyaan";
と書いて、「んん?unlessのとこって真になるべき条件やんね?」「どやったっけ?」でGoで書いた方に戻って確認して、
なんか自信が無いから
# Perl(2) return 0 if $neko ne "nyaan";
って書いて演算子を反転してunlessにして、という面倒くさいことをやる機会が増えました。
とは言え、しばらくPerlのコードを書いているとunless 真になるべき条件で分かりやすいやん?と思うのですが、
しばらくPerlから離れていると「unlessで条件が書いてるんやけどどっちが正しい処理やったっけ?」で読めなくなってる有様です。
半年以上もunlessが無い言語でいろいろ書いてたのでunlessがある言語で書いてるコードをみるとunless 真偽値はマァ良いとしてunless $nyaan == 22とか「え?んん?」って一瞬で理解できなくなってる、もうネコとして生きていくしかない。
— ネコ物質¹³⁰³¹ (@azumakuniyuki) April 5, 2025
Rubyの方はもっと読めない
returnとかnextとか後置unlessで且つ後ろにつける条件は==とかeqとか肯定文*2に限定して使っていますが、
Perlは暫く見ているとunless文が読めるのに対して、どういうわけかRubyの方は$があるか無いか程度の違いにもかかわらず
unlessで書いた式の条件が読めないと言えるぐらい理解に時間がかかるようになってて
「もうなんか読めへん理由は分からんけどunlessやめるわ💢」ってことで、少し前に90%以上のunlessをif`に書き換えました。
rb-sisimai(0) % find lib -type f -exec grep unless {} + | wc -l
32 ←元々Perlと同じく400行ぐらいあった
RubyはPerlほど量を書いていないので、単に目とアタマが慣れていなくて読めないだけかもしれませんが、大量のunlessを減らしました。
Perlの方はまだ結構あります、まぁRubyほど読めないことも無かったので。
p5-sisimai(0) % find lib -type f -exec grep unless {} + | wc -l
442
読めなくなった理由は単に年を取ってアタマの性能が落ちたことによるものかもしれない気がしないでもない雰囲気もなくはない
*3ので、
また、三言語で同じものを作っててコードの見た目も寄せているので、Perlもunlessをなるべくifに変えた方が良いかなぁとは思っています。
unlessの簡潔さ
for my $e ('from', 'by') { # Remove square brackets from the IP address such as "[192.0.2.25]" next unless defined $token->{ $e }; next unless length $token->{ $e }; next unless index($token->{ $e }, '[') == 0; $token->{ $e } = shift Sisimai::RFC791->find($token->{ $e })->@* || ''; }
これはメールのReceived:ヘッダーに書いているIPアドレスが妥当なものであるかどうか*4
を確認するコードの抜粋でして、ifに書き換えると次のようになります。
for my $e ('from', 'by') { # Remove square brackets from the IP address such as "[192.0.2.25]" next if !defined $token->{ $e }; next if length($token->{ $e }) == 0; next if index($token->{ $e }, '[') != 0; $token->{ $e } = shift Sisimai::RFC791->find($token->{ $e })->@* || ''; }
二番目と三番目はともかく、definedに付ける否定演算子!が見にくいというか細いので、そろそろ老眼の年とか考えると!はあんまり使いたくないなぁと
思うのですが、
next if defined($token->{ $e }) != 1; next if defined($token->{ $e }) eq "";
真偽値としての1であることは分かっていても整数値として評価するのもなんか変な感じがしますし、偽の場合は0が返ってくるわけでもない
*5みたいなので、unlessで書く方が簡潔である
*6と思います。
となると、一ヶ所だけunlessで残りはifってものちょっと収まりが悪い気がしますので、三つともunless で揃えたいのが人情です。
目に優しい否定文
この節は本筋とは無関係な余談であり八つ当たりみたいな内容ですが、否定演算子の話が出てきたので横道に逸れると、
!って一文字で動作が大きく変わるのに細くて目立たないので#define ⚠️ !とか#define ❗ !みたいなことが出来れば良いと思いつつも
例えば否定演算子として使うときだけ太字になるとか、絵文字は流石にちょっと...という時もあるので字面がイカれてるけど!!!って書くとか、
いろいろ思案した結果、Goではなるべく== falseと書く*7ようになりました。
!=は大丈夫なんやけどboolを評価する時にShift押しが弱くてif 1e {になってるのを見逃してコンパイルエラーを起こしたり} if le {に見間違えたりと加齢が関係してるかもしれない何かでアレやしif e == false {って書くようになった}}
— ネコ物質¹³⁰³¹ (@azumakuniyuki) November 2, 2024
人が見たら無駄に冗長なコードと見えるかもしれませんが、自分しかコミットしないコードですし、誤読したり認識に時間がかかるよりはマシってことで。
アタマの健康
一方で、unlessはそのまま残しておいて移植するときはアタマの体操的な観点で取り組めば良いのと違うの?という考えもあります。
何年後にそうなるかは知りませんし、そうならない可能性もありそうな気がしますが、機械が書くので人間は直接コードを書かなくなっても
健康診断のチラシとかに「アタマの健康のためにプログラムを書きましょう」みたいなことが書いてある世界になってるかも知れません。
現代におけるパズルとか数独みたいな位置づけです。
生きのこり
あるいは審判の日を超えたターミネーター的な世界になって捕らえた機械のプログラムを書き換える必要が出てきた際に手も足も出ない若者を押しのけて 「なんやジジィ!」と怒鳴られながらもサラサラっと書き換えて「いいか小僧ども、この時代に老いぼれを見たら『生き残り』と思え」 ってゴールデンカムイの土方さんみたいなセリフを発するためにもプログラムを読み書きする能力は維持したいものです。
松の内どころか年すら明けてないのですが寒中見舞い申し上げます。