Este comando está definido?

Conjuntos de macros dos primeiros dias da programação TeX podem ser testados para verificar os comandos existem usando

\ifx \command \undefinedstuff› …
(que, evidentemente, verifica que o comando não existe). Programadores do LaTeX podem fazer uso do comando interno
\@ifundefined{cmd name}{action1}{action2}
que executa a action1 se o comando estiver indefinido, e a action2 se ele estiver definido (cmd name é apenas o nome do comando, omitindo o caractere ‘\’).

O comando \@ifundefined está baseado na sequência

\expandafter \ifx \csname cmd name\endcsname \relax
que se baseia na maneira como o \csname funciona: se o comando não existir, ele simplesmente o cria como um alias do \relax.

Então, o que há de errado com essas técnicas?

Usar o \undefined é assumir levianamente que o comando está, de fato, não definido. Isso não é totalmente seguro; poder-se-ia usar um nome mais improvável, mas isso pode simplesmente dificultar a identificação de um problema quando as coisas derem errado. Programadores do LaTeX que usam a técnica normalmente empregam \@undefined, adicionando um único nível de obscuridade.

O mecanismo de \@ifundefined tem a infeliz propriedade de poluir o “namespace”: cada teste que resulta indefinido adiciona um nome ao conjunto do TeX e, muitas vezes, todos aqueles nomes “\relax” não servem para nada. Mesmo assim (infelizmente), existem lugares no código do LaTeX onde se depende da existência do \relax, após o teste, por isso não podemos fugir do \@ifundefined completamente.

David Kastrup oferece o (bem complicado)

{\expandafter}\expandafter\ifx \csname cmd name\endcsname\relax ...
que “cria” o comando \relax dentro do grupo do primeiro \expandafter, e o esquece novamente depois que o teste é feito. O teste é tão bom quanto o que se pode fazer com macros.

O sistema e-TeX vem nos socorrer aqui: ele define duas novas primitivas:

Então, em um sistema baseado em e-TeX, as duas cláusulas condicionais a seguir fazem a mesma coisa:
\ifdefined\foo
  \message{\string\foo\space is defined}%
\else
  \message{no command \string\foo}%
\fi
%
\ifcsname foo\endcsname
  \message{\string\foo\space is defined}%
\else
  \message{no command \string\foo}%
\fi
No entanto, depois de usar o \@ifundefined{foo}…, do LaTeX, as condicionais vão detectar o comando como “existente” (desde que ele tenha sido \let para o \relax); por isso, é importante não misturar mecanismos para detectar o estado de um comando.

Como a maioria das distribuições hoje em dia usa o e-TeX como base executável para a maioria dos pacotes, é esperado que essas duas primitivas apareçam amplamente em novos pacotes de macros.


Do you have any question? Ask on: latex.net.br - we love qood questions!