This addresses the more general OP question, "do there exists general recommendations/practices to follow (or perhaps to comply with) when writing user defined commands"? The OP asked me to convert my comments into an answer, so here goes.
\relax
with regard to Numbers and Dimensions
The TeXbook, p.71 says that "the control sequence \relax
after .5em
prevents TeX from thinking that a keyword is present, in case the text following [the dimension] just happens to begin with plus
or minus
." So the \relax
following a dimension prevents the accidental interpretation of what follows as part of a gluey dimension. The following shows the issue. See what difference the \relax
makes in the output:
\newlength\x
\x=1ex Plus 1pt to your score. \the\x\par
\x=1ex\relax Plus 1pt to your score. \the\x
Similar need to decisively terminate numbers can also arise unexpectedly, as shown nicely by Ryan's answer to this question, Use of \relax after \ifnum ... \fi construction. Here is an example of it, the 2nd part showing it with the \relax
, the 1st part without:
\documentclass{article}
\newcount\minleft
\newcount\timehour
\begin{document}
\time=724\relax
\timehour=9
\ifnum\time>720\advance\timehour by-12\fi%\relax
\number\timehour:
\time=724\relax
\timehour=9
\ifnum\time>720\advance\timehour by-12\fi\relax
\number\timehour:
\end{document}
Without the \relax
, the subsequent code is interpreted as part of a number calculation.
As David noted in the comments, however, there is always an exception. He points out that if a number calculation is part of a \typeout
, then the \relax
will show up explicitly in the log file, which may not be desired. He recommended to compare the outputs of \typeout{\ifnum3=3 yes\else no\fi}
with \typeout{\ifnum3=3\relax yes\else no\fi}
.
Brackets [ ]
and Optional Arguments
With \newcommand
definitions, optional arguments are delimited by bracket pairs [ ]
. Unlike braced groups which may be effectively nested in a balanced way, the \newcommand
parsing does not allow for nesting of bracketed groups (see \NewDocumentCommand
for an alternative). That means that if you are creating a macro for a user, you have to consider whether the user would ever use a left bracket as part of his optional argument, because it will break the compile. The workaround is to group with braces any brackets used in an optional argument associated with a \newcommand
definition.
Indentation and Vertical Mode
LaTeX indents paragraphs by default. If you are creating a macro, make sure that it behaves the way you want it to, if employed at the beginning of a paragraph, while TeX is still in vertical mode. If not, typical fixes include incorporating \noindent
and/or \leavevmode
at the beginning of your macro definition.
Note the vertical placement of the margin note relative to the first line of the paragraph, for the cases shown in the MWE below. The error in the second case is because the \mnote
was called at the beginning of the line, without leaving vertical mode.
\documentclass{article}
\usepackage{lipsum}
\newcommand\mnote[1]{\marginpar{\footnotesize#1}}
\begin{document}
Here is my margin note\mnote{Hi Mom}. \lipsum[3]
\mnote{Hi Mom}Here is my margin note. \lipsum[3]
\renewcommand\mnote[1]{\leavevmode\marginpar{\footnotesize#1}}
\mnote{Hi Mom}Here is my margin note. \lipsum[3]
\end{document}
\relax
. Examples:\mylength=3pt\relax
,\ifnum\x=3\relax...\fi
. The same applies to closing out a\dimexpr
and a\numexpr
.[]
inside of an optional argument to\newcommand
. So if your\newcommand
structure allows a user to provide an optional argument, and if a bracket might conceivably be contained in the optional argument, it must be grouped. Similarly, a left bracket ([
)cannot be the first token of user data (for example,#1
) following a linebreak separator\\#1
, without being misinterpreted as an optional argument. To avoid this, use\\{}#1
.\relax
in the resulting token stream, which isn't always desirable, compare\typeout{\ifnum3=3 yes\else no\fi}
to\typeout{\ifnum3=3\relax yes\else no\fi}