Comment tester si une commande est définie?
Méthodes traditionnelles
En TeX
Voici ce qu'on trouve dans les anciennes macros écrites en
pour tester l'existence d'une commande
<commande>
:
\ifx\<commande>\undefined<code à exécuter>
(ceci exécute le code si la commande n'existe pas, bien sûr).
En LaTeX
Quand on programme en , on peut directement utiliser
\@ifundefined{<cmd name>}{<action1>}{<action2>}
,
qui exécute <action1>
si la commande n'est pas définie,
et <action2>
dans le cas contraire
(<cmd name>
est le nom de la commande tout nu, sans son antislash \
).
La macro \@ifundefined
utilise ce mécanisme:
\expandafter \ifx \csname cmd name\endcsname \relax
qui repose sur le fonctionnement de \csname
:
si la commande n'existe pas, il la crée comme alias de \relax
.
Qu'est-ce qui ne va pas avec ces méthodes ?
Using \undefined
blithely assumes that the command is indeed not
defined. This isn't entirely safe; one could make the name more
improbable, but that may simply make it more difficult to spot a
problem when things go wrong. LaTeX programmers who use the
technique will typically employ \@undefined
, adding a single
level of obscurity.
The original \@ifundefined
mechanism had the unfortunate property of
polluting the name space: each test that turns out undefined adds a
name to the set TeX is holding, and often all those \relax
names serve no purpose whatever.
David Kastrup offers the (rather tricky):
{\expandafter}\expandafter\ifx \csname cmd name\endcsname\relax ...
which “creates” the \relax
-command inside the group of the first
\expandafter
, therefore forgets it again once the test is done.
The test is about as good as you can do with macros.
The ε-TeX system system comes to our help here: it defines two new primitives:
\ifdefined
, which tests whether a thing is defined (the negative of comparing with\undefined
, as it were), and\ifcsname cmd name\endcsname
, which does the negative of\@ifundefined
without the\relax
-command side-effect.
So, in an ε--based system, the following two conditional clauses do
the same thing:
\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
However, after using the original LaTeX \@ifundefined{foo}…
,
the conditionals will detect the command as “existing”
(since it has been \let
to \relax
) ; so it is important
not to mix mechanisms for detecting the state of a command.
In the 2018 release, the definition of
\@ifundefined
was adapted
to use the -TeX
\ifcsname
and now tests for a command being undefined or \relax
without the side effect of defining undefined commands to \relax
.
Source: Is this command defined?