Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
2_programmation:macros:cette_commande_est_elle_definie [2018/06/03 13:15]
joseph.wright
2_programmation:macros:cette_commande_est_elle_definie [2021/09/27 21:41]
bdumont Traduction et remaniement pour mettre les solutions modernes et fiables en premier
Ligne 1: Ligne 1:
---- +====== Comment tester si une commande est définie======
-title: Is this command defined? +
-category: programming +
-tags: macros +
-permalink: /FAQ-isdef +
----+
  
-Macro sets from the earliest days of TeX programming may be +===== En TeX =====
-observed to test whether commands exist by using +
-`\ifx\<command>\undefined` &lsaquo;_stuff_&rsaquo; &hellip; +
-(which of course actually tests that the command _doesn't_ +
-exist).  LaTeX programmers can make use of the internal command +
-  `\@ifundefined{cmd name}{action1}{action2}` +
-which executes `action1` if the command is undefined, and +
-`action2` if it is defined +
-(_cmd name_ is the command name only, omitting the `\` character).+
  
-The `\@ifundefined` command is based on the sequence +Le programme <latex>\TeX{}</latex> originalécrit par Donald Knuth, ne définit pas de commandes dédiées à cette tâcheHeureusement, [[1_generalites:glossaire:qu_est_ce_que_etex|ε-TeX]] définit deux primitives supplémentaires :
-```latex +
-\expandafter \ifx \csname cmd name\endcsname \relax +
-``` +
-which relies on the way `\csname` works: if the command doesn'+
-existit simply creates it as an alias for `\relax`.+
  
-So: what is wrong with these techniques?+  * ''\ifdefined'' 
 +  * ''\ifcsname cmd name\endcsname''
  
-Using `\undefined` blithely assumes that the command is indeed not +Les deux commandes utilisées dans l'exemple qui suit produisent le même effet :
-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 +<code latex>
-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) +
-```latex +
-{\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 [&epsilon;-TeX system](FAQ-etex) 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 &epsilon;-TeX-based system, the following two conditional clauses do +
-the same thing: +
-```latex+
 \ifdefined\foo \ifdefined\foo
   \message{\string\foo\space is defined}%   \message{\string\foo\space is defined}%
Ligne 69: Ligne 22:
   \message{no command \string\foo}%   \message{no command \string\foo}%
 \fi \fi
-``` +</code> 
-However, after using the original LaTeX + 
-`\@ifundefined{foo}`&hellip;, the conditionals will detect the +However, after using the original LaTeX ''\@ifundefined{foo}...'', 
-command as "existing" (since it has been `\letto `\relax`); +the conditionals will detect the command as "existing" 
-so it is important not to mix mechanisms for detecting the state of a +(since it has been ''\let'' to ''\relax'') ; so it is important 
-command.+not to mix mechanisms for detecting the state of a command. 
 + 
 +===== En LaTeX ===== 
 + 
 +Quand on programme en <latex>\LaTeX{}</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>\LaTeX{}</latex> antérieure à 2018, il faut éviter de mélanger du code qui utilise les primitives d'ε-TeX 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>\LaTeX{}</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 <latex>\TeX{}</latex> 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>\LaTeX{}</latex>, ne fait que déplacer le problème. 
 + 
 +La macro ''\@ifundefined'', elle, est définie dans le noyau de <latex>\LaTeX{}</latex>, ce qui permet d'éviter ce problème. Cependant, avant 2018, elle était définie de la manière suivante : 
 + 
 +<code latex> 
 +\expandafter \ifx \csname cmd name\endcsname \relax 
 +</code> 
 + 
 +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 <latex>\TeX{}</latex>
 +  * Si le même nom de commande est testé ensuite avec la primitive ε-TeX ''\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>\LaTeX{}</latex> pour être basée sur la primitive ε-TeX ''\ifdefined'', David Kastrup a proposé la solution suivante : 
 + 
 +<code latex> 
 +{\expandafter}\expandafter\ifx \csname cmd name\endcsname\relax ... 
 +</code> 
 + 
 +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''
 + 
 +----- 
 +//Source:// [[faquk>FAQ-isdef|Is this command defined?]]
  
-In the 2016 LaTeX releasethe definition of `\@ifundefined` was adapted +{{htmlmetatags>metatag-keywords=(LaTeX,programmation LaTeX,tester si une macro est définie,savoir si une commande est définie) 
-to use the &epsilon;-TeX `\ifcsname` and now tests for a command being undefined or `\relax` +metatag-og:title=(Is this command defined?) 
-without the side effect of defining undefined commands to `\relax`.+metatag-og:site_name=(FAQ LaTeX francophone) 
 +}}
  
2_programmation/macros/cette_commande_est_elle_definie.txt · Dernière modification: 2021/09/27 21:41 de bdumont
CC Attribution-Share Alike 4.0 International
Driven by DokuWiki Recent changes RSS feed Valid CSS Valid XHTML 1.0