La meilleure raison de définir ses propres commandes en LaTeX, c’est-à-dire des macros, n’est pas d’économiser des frappes. Imaginons une thèse où chaque vecteur est composé \mathbf{v}, quatre cents fois, et un directeur qui préfère finalement des flèches. Si ces vecteurs avaient été écrits \vect{v}, adossés à un seul \newcommand, tout le changement tiendrait en une ligne du préambule ; sinon, ce sont quatre cents corrections minutieuses. Une macro est l’endroit où l’on garde le droit de changer d’avis. Cette page part de \newcommand et de ses arguments, démêle \renewcommand et \providecommand, explique où passe l’espace qui suit un nom de macro, et finit par les commandes fragiles, \protect et le moderne \NewDocumentCommand.
Définir sa propre commande avec \newcommand
Toute la syntaxe tient en une ligne : \newcommand{\name}{definition}. Le premier argument est le nom voulu, le second ce qu’il représente, et dès lors chaque \name tapé est remplacé par definition. Sa place naturelle est le préambule, avant \begin{document}. C’est ici que l’histoire des vecteurs paie : le nom \vect désigne un sens, pas une apparence. Écrire « ceci est un vecteur » au lieu de « ceci est en gras » laisse la décision — gras ou flèche au-dessus — en un seul endroit. C’est le marché que LaTeX propose déjà : on écrit \section plutôt que de composer du gras 14pt à la main exactement pour cette raison.
% preamble: one line decides how every vector in the document looks
\usepackage{amsmath,amssymb}
\newcommand{\vect}[1]{\mathbf{#1}}
% \newcommand{\vect}[1]{\vec{#1}} % swap this line, the whole thesis follows
% semantic names for things you refer to constantly
\newcommand{\R}{\mathbb{R}}
\newcommand{\dd}{\mathrm{d}}
% body
\[ \vect{v} \cdot \vect{w} = \lvert \vect{v} \rvert \, \lvert \vect{w} \rvert \cos\theta \]
\[ \int_{\R} f(x) \, \dd x \]Macros à arguments, et l’argument optionnel
Pour faire varier le contenu à chaque appel, on met le nombre d’arguments entre crochets après le nom et on les récupère dans la définition sous la forme #1, #2, etc. : \newcommand{\name}[⟨nargs⟩]{... #1 #2 ...}. Il n’existe qu’un seul plafond dur — les paramètres vont de #1 à #9, neuf au maximum. Le plus curieux est qu’en demander un dixième produit ! You already have nine parameters., message qui vient du moteur TeX et non de LaTeX. La limite appartient à la primitive \def sous-jacente ; \newcommand ne peut pas la desserrer. Avoir besoin de plus de neuf arguments signale en général qu’il faut passer à des options clé-valeur plutôt qu’à des arguments positionnels.
% two mandatory arguments: a number and a unit
\newcommand{\unit}[2]{#1\,\mathrm{#2}}
$a = \unit{9.8}{m/s^2}$On peut aller plus loin et rendre le premier argument optionnel, avec une valeur par défaut. C’est la forme à crochets doublés, \newcommand{\name}[⟨nargs⟩][⟨default⟩]{...} : #1 devient l’argument optionnel, et un appel sans lui substitue ⟨default⟩. On écrit ensuite \name{...} pour prendre la valeur par défaut ou \name[x]{...} pour fixer #1 à x ; les arguments obligatoires restants se comptent à partir de #2. Le piège est dans le décompte : [⟨nargs⟩] est le nombre total d’arguments, l’optionnel compris. Dans l’exemple ci-dessous, [2][2] signifie « deux arguments, le premier optionnel avec 2 par défaut ».
% two arguments in total; the first is optional and defaults to 2
\newcommand{\pow}[2][2]{(x + y)^{#1}_{#2}}
$\pow{n}$ % -> (x + y)^2_n
$\pow[3]{n}$ % -> (x + y)^3_n
% starred form: the argument may not contain a blank line
\newcommand*{\keyword}[1]{\textsf{#1}}Deux détails méritent d’être ajoutés. D’abord, omettre [⟨default⟩] n’équivaut pas à écrire des crochets vides [] : ces derniers donnent un argument optionnel dont la valeur par défaut est la chaîne vide. Ensuite, la forme étoilée \newcommand* construit une macro « courte » dont l’argument ne peut pas contenir de ligne vide (donc pas de \par). Cela ressemble à une restriction mais c’est un diagnostic : en cas d’accolade fermante oubliée, ! Paragraph ended before \keyword was complete. apparaît près de l’erreur. Sans l’étoile, TeX lit tranquillement le paragraphe suivant, puis celui d’après, comme partie de l’argument, et l’erreur ne surgit que des pages plus loin. Mettre * sur toute macro qui n’a pas vocation à franchir un paragraphe fait gagner beaucoup de temps.
La différence entre \newcommand, \renewcommand et \providecommand
Les trois prennent leurs arguments exactement de la même façon ; ce qui change, c’est leur réaction face à un nom déjà pris. \newcommand refuse et s’arrête, \renewcommand écrase, et \providecommand s’efface en silence et conserve la définition existante. Appliqué à un nom existant, \newcommand s’arrête donc sur ! LaTeX Error: Command \emph already defined., tandis que \renewcommand appliqué à un nom indéfini s’arrête sur ! LaTeX Error: Command \foo undefined. Ces deux erreurs forment une paire et protègent des deux côtés : contre l’écrasement accidentel, et contre la croyance d’avoir écrasé quelque chose alors qu’il n’en est rien.
Une curiosité : écrire \newcommand{\endnotes}{...} s’arrête sur Command \endnotes already defined. alors qu’aucune commande de ce nom n’existe nulle part. La deuxième ligne du message vend la mèche — elle poursuit par Or name \end... illegal, see p.192 of the manual. La vérification de nom dans latex.ltx constate d’abord que le nom est indéfini, puis exige en plus que ses trois premières lettres ne soient pas end et que le nom ne soit pas relax. Comme \end{itemize} fonctionne en appelant en interne \enditemize, laisser inventer des noms commençant par end casserait l’appariement des environnements : tout le préfixe est donc réservé. La formule « already defined » n’est qu’un message grossier couvrant les deux cas.
| Commande | Face à un nom existant | Usage principal |
|---|---|---|
\newcommand | S’arrête avec une erreur | Créer une nouvelle commande en sécurité |
\renewcommand | L’écrase (erreur si indéfini) | Retravailler une commande existante |
\providecommand | Ne fait rien (garde l’ancienne) | Fichiers de style chargés plusieurs fois |
\DeclareRobustCommand | L’écrase et note dans le journal | Commandes robustes pour arguments mobiles |
La répartition pratique est nette. \renewcommand est la porte marquée « remplacer ce que LaTeX fournit déjà » ; changer la puce d’une liste avec \renewcommand{\labelitemi}{--} en est le cas classique. \providecommand déclare « fournir ceci si personne d’autre ne l’a fait », de sorte qu’un fichier de style personnel survive à une double lecture depuis deux endroits. Dans l’exemple ci-dessous, \vect existe déjà : \providecommand ne fait donc rien et la définition en gras subsiste. Enfin, \DeclareRobustCommand est la vedette de la section suivante : il ne s’arrête pas sur un nom existant, il laisse simplement une ligne du type LaTeX Info: Redefining \emph on input line 2. dans le .log. Consigner l’écrasement plutôt que l’exécuter en silence, voilà sa vraie différence avec \renewcommand.
% replace something the class already defines
\renewcommand{\labelitemi}{--}
% define only if nobody else did; here \vect exists, so this line is a no-op
\providecommand{\vect}[1]{\vec{#1}}
% redefine on purpose, and say so in the log
\DeclareRobustCommand{\emph}[1]{\textbf{#1}}Pourquoi l’espace après une macro disparaît, et ce que \xspace corrige
Un nom de commande composé uniquement de lettres s’arrête à la première non-lettre, et les espaces qui suivent sont avalés comme marque de fin du nom. Avec \newcommand{\lab}{Knuth Lab} dans le préambule, taper \lab was founded. imprime donc « Knuth Labwas founded. » L’espace n’a pas disparu : TeX l’a consommé pour déterminer où s’arrête le nom \lab. L’exception est révélatrice : \$ de conserve son espace et compose « $ de ». \$ est un symbole de contrôle d’un seul caractère non alphabétique ; son nom est complet après ce caractère et rien ne justifie de lire plus loin. Le piège ne concerne donc que les noms de commande écrits avec des lettres.
\usepackage{xspace}
\newcommand{\lab}{Knuth Lab}
\newcommand{\labx}{Knuth Lab\xspace}
\lab was founded. % -> Knuth Labwas founded.
\lab{} was founded. % -> Knuth Lab was founded.
\lab\ was founded. % -> Knuth Lab was founded.
\labx was founded. % -> Knuth Lab was founded.
\labx, and a comma. % -> Knuth Lab, and a comma.Trois remèdes existent. Le plus courant est une paire d’accolades vide, \lab{}, qui marque la fin du nom ; vient ensuite l’espace de contrôle \lab\ ; et troisièmement \xspace, du package xspace. L’astuce de \xspace est qu’il n’ajoute pas l’espace inconditionnellement : il jette d’abord un œil au token suivant. La liste d’exceptions de xspace.sty contient , . ' / ? ; : ! ~ - ) et les accolades fermantes, ainsi que \footnote et consorts ; aucun espace n’est inséré devant eux. C’est pourquoi \labx, and compose correctement « Knuth Lab, and ». Le package fait partie du lot tools de LaTeX et a été écrit à l’origine par David Carlisle ; \xspaceaddexceptions permet d’allonger la liste. Il faut en connaître le coût : \xspace est une ruse d’anticipation, inutile pour les macros à arguments (qui finissent de toute façon par }) et parfois surprenante à l’intérieur de l’argument d’une autre macro. Dans le doute, {} reste la plus sûre des trois.
Commandes fragiles, arguments mobiles, \protect et \DeclareRobustCommand
Une macro personnelle peut se briser brusquement dans un titre de section ou une légende. La cause en est l’argument mobile. Le texte de \section{...} n’est pas seulement composé dans le corps : il est aussi écrit dans le fichier .aux pour la table des matières et transmis à l’en-tête courant. Le même contenu « se déplace » ailleurs. \caption{...}, \thanks{...} et les expressions @{...} de tabular et array se comportent de même. Une commande dont le code perd son sens s’il est développé au moment de l’écriture est dite fragile ; celle qui survit à cette écriture telle quelle est robuste.
Le remède classique est \protect, placé juste avant une commande fragile pour dire « ne développe pas ceci ici, écris-le tel quel ». Il protège exactement une commande à la fois. Bonne nouvelle toutefois : depuis la version de LaTeX d’octobre 2019, un grand nombre de commandes autrefois fragiles ont été rendues robustes. Le changement est consigné dans LaTeX News 30, section « Making more user commands robust » ; il va jusqu’à \begin et \end, si bien que des environnements entiers fonctionnent désormais dans un titre. L’irréductible reste \verb : placé dans un titre de section, il arrête la compilation sur ! LaTeX Error: \verb illegal in argument. (en entraînant le plus souvent ! Paragraph ended before \@sect was complete.). Celui-là, \protect ne le sauve pas ; dans un titre ou une légende, la solution pratique est de le réécrire en \texttt{...}.
% \verb cannot go here at all -- rewrite it
\section{The \texttt{\textbackslash par} primitive}
% a macro that is robust from the start, even though \ifmmode is fragile
\DeclareRobustCommand{\seq}[2][n]{%
\ifmmode #2_{1}\ldots #2_{#1}\else\textbf{??}\fi
}
\section{Sequences $\seq{x}$} % works without \protectPour ses propres macros, les définir robustes dès le départ avec \DeclareRobustCommand est plus fiable que de penser à \protect à chaque fois. Les arguments s’écrivent exactement comme avec \newcommand, et même si le corps mêle du code fragile comme \ifmmode, la commande obtenue survit à un argument mobile. Le \seq ci-dessus est l’exemple du clsguide de LaTeX lui-même, écrit pour démontrer précisément cela. Le coût est une légère perte d’efficacité : inutile donc de rendre robuste une macro qui n’apparaîtra jamais dans un titre ou une légende. La seule question utile est de savoir si la macro peut un jour se retrouver dans la table des matières.
\NewDocumentCommand : la manière moderne de définir
\newcommand ne sait construire qu’une seule forme : au plus un argument optionnel entre crochets, suivi d’arguments obligatoires. \NewDocumentCommand{\name}{⟨arg-spec⟩}{...} fait sauter ce plafond. Au lieu d’un nombre d’arguments, on lui passe une spécification d’arguments (arg-spec) : une chaîne de lettres nommant le type de chacun. C’était à l’origine une fonction du package xparse, mais la version du 1er octobre 2020 l’a intégrée au noyau LaTeX (module ltcmd) ; elle s’utilise donc aujourd’hui sans \usepackage{xparse}. LaTeX News 32 consigne ce transfert.
| Spécificateur | Signification | Arrivée dans le corps |
|---|---|---|
m | Argument obligatoire | Un #1 ordinaire, etc. |
o | Argument optionnel [...] | Marqueur « sans valeur » si absent |
O{default} | Optionnel, avec valeur par défaut | La valeur par défaut si absent |
s | Étoile * optionnelle | Testée avec \IfBooleanTF |
C’est là son avantage décisif sur \newcommand : il accepte plusieurs arguments optionnels et traite les variantes étoilées comme une fonctionnalité de plein droit. Un s fait arriver dans #1 un booléen indiquant la présence de l’étoile, sur lequel on branche avec \IfBooleanTF{#1}{étoilé}{simple}. Changer le préfixe entre New, Renew, Provide et Declare donne les équivalents de \newcommand, \renewcommand, \providecommand et de l’écrasement inconditionnel. Pour du code neuf, cette interface peut devenir le choix par défaut — sachant que \newcommand n’a ni disparu ni vieilli et reste parfait pour une définition courte à un ou deux arguments.
% s = optional star, m = mandatory argument
\NewDocumentCommand{\diff}{s m}{%
\IfBooleanTF{#1}%
{\frac{\mathrm{d}}{\mathrm{d}#2}}% starred: d/dx
{\mathrm{d}#2}% plain: dx
}
$\diff{x}$ % -> dx
$\diff*{x}$ % -> d/dx
% O{...} gives an optional argument with a default
\NewDocumentCommand{\note}{O{note} m}{\textbf{#1:} #2}Nommer ses macros sans collision, et où ranger les définitions
Le meilleur outil contre les collisions de noms est \newcommand lui-même. Écraser d’emblée avec \renewcommand ou \def ne dit jamais ce qui a été détruit ; définir d’abord avec \newcommand fait apparaître un already defined qui signale aussitôt que le nom est pris. C’est précisément pourquoi il ne faut pas aplatir à la légère des commandes du noyau ou d’un package avec \renewcommand. Pour ses propres noms, éviter les trop courts et préférer un préfixe propre au projet (\myR, \bookTitle). Les noms courts d’opérateurs mathématiques sont particulièrement pris — \ker, \deg, \arg, \Re — donc si l’on veut \R, un essai avec \newcommand vaut la peine.
Trop de macros nuit autant que pas assez. Une abréviation extrême comme \newcommand{\x}{\xi} est un code secret pour soi-même dans six mois et pour un coauteur. Réserver les macros à ce qui est souvent répété, susceptible de changer en bloc ou digne d’un nom sémantique ; le reste se lit mieux écrit tel quel. Le test est simple : le nom se comprend-il d’un coup d’œil ? \vect oui, \x non.
Reste la question de l’emplacement. Pour un seul article, le préambule suffit ; mais un livre découpé en fichiers par chapitre, ou plusieurs articles partageant une même notation, se gèrent plus facilement si les définitions vivent dans un fichier à part chargé par \usepackage. Un petit bonus s’y ajoute : à l’intérieur d’un .sty ou d’un .cls, @ compte comme une lettre, si bien que des noms internes comme \mybook@vecfont fonctionnent sans écrire \makeatletter. Comme un nom contenant @ ne peut pas être appelé depuis le corps du document, on obtient une distinction par le nom entre commandes publiques et commandes privées. Faire de même dans un préambule impose d’encadrer le code entre \makeatletter et \makeatother, une occasion d’erreur de plus.
% ---- mynotation.sty --------------------------------------------
\ProvidesPackage{mynotation}[2024/01/01 shared notation]
\RequirePackage{amsmath,amssymb}
% private: the @ makes it uncallable from the document body
\newcommand{\mynot@vecfont}[1]{\mathbf{#1}}
% public
\newcommand{\vect}[1]{\mynot@vecfont{#1}}
\newcommand{\R}{\mathbb{R}}
% ---- thesis.tex ------------------------------------------------
% \usepackage{mynotation}