--- myst: html_meta: keywords: LaTeX,programmation LaTeX,tester si une macro est définie,savoir si une commande est définie" --- # Comment tester si une commande est définie ? ## En TeX Le programme TeX original, écrit par Donald Knuth, ne définit pas de commandes dédiées à cette tâche. Heureusement, [eTeX](/1_generalites/glossaire/etex) définit deux primitives supplémentaires : - `\ifdefined` - `\ifcsname cmd name\endcsname` Les deux commandes utilisées dans l'exemple qui suit produisent le même effet : ```{noedit} \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. ## 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** `\`). Si vous utilisez une version de LaTeX antérieure à 2018, il faut éviter de mélanger du code qui utilise les primitives d'eTeX avec du code qui utilise `\@ifundefined` (voir ci-dessous pourquoi). Comme cela peut se produire d'une extension à l'autre, vous n'êtes jamais à l'abri d'une erreur... Notez également que, même après 2018, LaTeX va toujours renvoyer "vrai si l'on utilise `\@ifundefined` avec une commande définie comme un alias de `\relax`. ## Un peu d'histoire On trouve dans d'anciennes macros écrites en TeX le procédé suivant 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.) Le fonctionnement de cette commande repose sur le principe que `\undefined` n'est jamais défini (donc elle est égale à une autre commande non définie). Le problème est qu'il ne s'agit que d'une convention qui peut être ignorée par un autre auteur de macros : il y a donc toujours un risque que cette macro soit définie dans une extension chargée par l'utilisateur... Utiliser `\@undefined`, comme on peut le voir dans certaines macros LaTeX, ne fait que déplacer le problème. La macro `\@ifundefined`, elle, est définie dans le noyau de LaTeX, ce qui permet d'éviter ce problème. Cependant, avant 2018, elle était définie de la manière suivante : ```{noedit} \expandafter \ifx \csname cmd name\endcsname \relax ``` Elle utilisait la propriété suivante de `\csname` : si la commande n'existe pas, elle est créée comme alias de `\relax`. Cette approche présente deux inconvénients : - Chaque utilisation de `\@ifundefined` avec un nom de commande qui n'existe pas crée cette commande, définie comme identique à `\relax` ; si cette commande n'est pas redéfinie ensuite, elle est conservée inutilement en mémoire par le moteur TeX ; - Si le même nom de commande est testé ensuite avec la primitive eTeX `\ifdefined` (par exemple dans le code d'une autre extension), le résultat sera un faux positif, car cette primitive considère aussi comme définie la commande `\relax` et ses alias. Avant que `\@ifundefined` ne soit redéfinie dans le noyau LaTeX pour être basée sur la primitive eTeX `\ifdefined`, David Kastrup a proposé la solution suivante : ```{noedit} {\expandafter}\expandafter\ifx \csname cmd name\endcsname\relax ... ``` La commande testée est créée et définie comme `\relax` à l'intérieur du groupe dans lequel est inclus le premier `\expandafter` : elle n'est donc pas conservée en mémoire après l'exécution de `\@ifundefined`. :::{sources} [Is this command defined?](faquk:FAQ-isdef) :::