なんとなく、e-TeX の拡張機能の解説をするシリーズを始めていた。例によって、いつまで続くかは不明。初回はこの 2 つ。((なお、冒頭の紹介文での説明は LaTeX と非依存の形で行うが、その後の解説文の中では一般的に LaTeX の \makeatletter
の状態を前提とする。))
\ifdefined〈トークン〉
[if-トークン] : 〈トークン〉が定義済であるかを判定する。\ifcsname〈文字列〉\endcsname
[if-トークン] : 「\〈文字列〉」という制御綴が定義済であるかを判定する。\csname
のように、該当の制御綴を\relax
にすることはない。
このうち、\ifdefined〈トークン〉
の方は、非 e-TeX でも \ifx〈トークン〉\@undefined
((\@undefined
は LaTeX で「未定義である」ことが約束されたトークン。))の逆条件で完全に代用できる。しかし、\ifcsname
は非 e-TeX で完全に代替することはできない拡張機能である。
非標準な(カテゴリコード 11 以外の文字を含む、可変部分を含む、等)制御綴が定義されているかを調べたい場合、例えば \[xx@foo/\xx@id]
((「xxx」という文字列からなる制御綴りを \[xxx]
と記述することにする。例えば、\csname 1+1=2\endcsname
の展開結果が \[1+1=2]
である。))(\xx@id
は文字列に展開されるマクロ)が定義済かを調べたい場合を考える。\ifcsname
を用いて次のように実現できる:
\ifcsname xx@foo/\xx@id\endcsname 〈真〉 \else 〈偽〉 \fi
しかしこういう処理は e-TeX 登場以前の TeX でのプログラミングでも度々用いられる。非 e-TeX では通常次のような構文を用いる:
\expandafter\ifx\csname xx@foo/\xx@id\endcsname\relax 〈真〉 \else 〈偽〉 \fi
ところが、この構文には「\[xx@foo/\xx@id]
が未定義の場合と \relax
と等価な場合の両方に真と判定される」、および「\[xx@foo/\xx@id]
が未定義の場合は \relax
と等価に定義(\let
)されるという副作用がある」という難点がある(これは \csname
がそういう副作用をもつからである)。そして、そういう「周知の癖」があるため、TeX プログラマは「非標準な制御綴については、未定義であることと \relax
であることは区別しない」という習慣に従ってきた。
ただ、何か理由があって、「非標準な制御綴について未定義と \relax
を区別したい」場合もある。そういう場合には \ifcsname
が非常に有効であると考えられる。
ただし、実は今の場合にも次のような非 e-TeX での対処法が知られている:
\begingroup\expandafter\endgroup
\expandafter\ifx\csname xx@foo/\xx@id\endcsname\@undefined
「\expandafter
の原理」に従うと、これは「\begingroup\endgroup\ifx\[xx@foo/\xx@id]\@undefined
」と等価になることが解るであろう。ここで、\csname
展開時に制御綴の \relax
への定義は行われているが、それはグループの中であり、直後にそのグループを抜けているので、結局定義はなかったかのように振舞う。
ただこれも \ifcsname
を使った判断(の逆条件)と全く等価ではない。なぜなら、「余計な \begingroup\endgroup
」があるからである。このことは「展開のみ行われる状況」(\edef
の置換テキストの中など)では本質的な違いを生む。\ifcsname
は展開可能であり、それ故に完全展開可能性が要求されるマクロの中で使われる可能性があり、このような場合は先の構文で代替することはできないのである。
ちなみに、次のようにすると、「制御綴が未定義と \relax
の両方で真と判断されるが、\relax
への定義は行われない」という処理になる:
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname xx@foo/\xx@id\endcsname\relax
これの動作原理を理解するのは最初の構文よりも難しい。\expandafter
と条件分岐が絡むからである。
非標準な制御綴の定義済を検査するのに専ら \ifcsname
を用いることにすれば、先述の「未定義と \relax
は区別しない」という習慣を捨てることができる。ただ、\csname
の副作用は当然 e-TeX でも残ったままなので、その点に注意が必要である。