マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

LaTeX が新しくなった話(補足2)

前回の続き)
カーネルと etex パッケージは互換性がない

新しい LaTeX では「たくさん」のレジスタが最初から使用可能になっていて、etex パッケージを読み込む必要がない、という話をした。これだけ聞くと、「じゃあ、etex のコードが移植されて最初から有効になっている、てことだな」と思った人もいるかも知れない。

しかし、実際は違っていて、新カーネルと etex パッケージでは、「拡張レジスタ領域(256 番以降)」の割当のロジックが多少異なっている。((etex パッケージは \loccount といった「局所的なレジスタ割当」の機能を有するが、新カーネルには該当の機能は存在しない。))そして、結果的に、カーネルにおいて etex パッケージを読み込むと割当が誤動作を起こす事例が存在する。ここではその例を紹介する。

\newdimen が破滅する話

次のようなソースを用意する。

[test.tex]
\documentclass{article}
% 本来のログ出力を端末にも出力させる.
\def\wlog{\immediate\write16 }
% 割当が拡張領域(256番以降)に達するまで繰り返し \newdimen\whiz
% を実行して(無駄に)割当を要求する.
\loop \newdimen\whiz \ifnum\allocationnumber<256 \repeat
% 対話モードに移行する...

\newXXX 命令を実行した時にはログに例えば「\foobar=\count42」のような形式のメッセージが出力される。これを端末に出力させるために \wlog を再定義した。この点を除けば LaTeX カーネルへの改変は行っていないことに注意してほしい。

この test.texコンパイルすると、以下のような出力の後に対話モードに入る。(行頭の * はプロンプト。)

This is pdfTeX, Version 3.14159265
……(略)……
(./test.tex
……(略)……
\whiz=\dimen104
\whiz=\dimen105
……(略)……
\whiz=\dimen232
\whiz=\dimen233
\whiz=\dimen256
)
*

この時点で、基本領域の dimen レジスタを使い尽くして拡張領域に移って、256 番のレジスタが使われている。(基本領域の後ろの 234〜255 番は別の目的で既に割当済なのでこの範囲は飛ばされている。)なので、今は \whiz\dimen256 である。これに実際に値を入れてみよう。

*\whiz=42pt

ここでもう一つ dimen を割り当ててみる。

*\newdimen\wham

*\wham=56pt

*\typeout{\the\whiz;\the\wham}
42.0pt;56.0pt

今のところは正常に機能しているようだ。

しかしここで etex パッケージを読み込んでみる。

*\usepackage{etex}\relax
(c:/usr/local/share/texmf-dist/tex/latex/etex-pkg/etex.sty
Package: etex 2015/03/02 v2.1 eTeX basic definition package (PEB,DPC)
\et@xins=\count87
)

特にエラーや警告は出てこない。ここで再び dimen を割り当てる。

*\newdimen\foo
Normal \dimen register pool exhausted, switching to extended pool.
\foo=\dimen256

なんと、既に \whiz に割り当てたはずの 256 番を重複して \foo に割り当てている! さらに続けてみる。

*\newdimen\bar \foo=100pt \bar=200pt
\bar=\dimen257

ここで再び \whiz\wham の値を調べてみると……

*\typeout{\the\whiz;\the\wham}
100.0pt;200.0pt

\whiz\foo が同じレジスタを指してしまっているので、\foo に書き込んだ値が \whiz にも反映されるという困った事態になっている。\wham\bar も全く同様である。

どうしてこうなった

LaTeX の新しいカーネルでは etex パッケージが誤動作を起こす、というと、一番ありそうな理由は「etex の方が追随できていない(古いままである)」であろう。しかしどうやらそうではないようだ。先の実験の(端末にも書かれた)ログ出力から判るように、etex の更新日付は 2015/03/02 とかなり新しい。それに etex.sty の中を見ると以下のような記述がある。

%% To ensure working in LaTeX 2015 release do define \newcount etc
%% with their pre 2015 LaTeX definitions

つまり、新しいカーネルに対応させた結果が今の状況でなのである。

単純に考慮漏れのために起きた不具合(つまりバグ)という可能性も考えられる。だがしかし、etex と新カーネルで異なるロジックを使っている以上、衝突が起こってしまうのはかなり自明なように思える。なんとなく、「実害がほとんどないので放置された」のではないかと疑っている。

今回の件で不具合が起こるのは、「既に『拡張領域』の割当が始まっている時に etex が読み込まれた」場合に限られる。以前の LaTeX であれば、「レジスタが足りない」というエラーが発生して結局失敗するケースなのである。といっても、「明確なエラーが出る」のが「エラーも出さずに滅茶苦茶な動作をする」のに変わるのは、やはり不適切であろう。

ただし、このようなケースが起こりにくいのも確かである。そもそもユーザが etex を読み込むのであれば普通はできるだけ早い段階で読み込もうとするだろう。実際には滅多に発生しないのかも知れない。