Comment tester si une commande est définie ?

Méthodes traditionnelles

En TeX

Voici ce qu'on trouve dans les anciennes macros écrites en \TeX{} 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 \LaTeX{}, 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 ε-\TeX{}-based system, the following two conditional clauses do the same thing:

  \message{\string\foo\space is defined}%
  \message{no command \string\foo}%
\ifcsname foo\endcsname
  \message{\string\foo\space is defined}%
  \message{no command \string\foo}%

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 \LaTeX{} release, the definition of \@ifundefined was adapted to use the $\epsilon$-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?

2_composition/macros/cette_commande_est_elle_definie.txt · Dernière modification: 2021/01/07 19:23 par jejust
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0