5

This question arise from my recent activity on user defined commands of various kind. In the answer to a recently posed question, @egreg pointed out to me the importance of not forgetting a % after the \end{minipage} environment delimiter (see also his other answer), and I also noticed that a forgotten space ir <CR><LF> had enormous (1ex!) impact on the correct placement of two adjacent \parbox-es, defined on two consecutive lines of code for reasons of convenience. Therefore my question is: apart from the observation made by Kopka and Daly ([1], §10.5.2 pp. 199-200), do there exist general recommendations/practices to follow (or perhaps to comply with) when writing user-defined commands, codes, etc. in order to avoid causing "strange" formatting problems?

[1] Kopka, Helmut, Daly, Patrick W. (2004), "Guide to LaTEX", 4th ed., Boston etc.: Addison-Wesley, pp. xii+597.

9
  • A line break is treated as a space, with a percent sign, this space is hidden. Don't know what answer you may be looking for?
    – Johannes_B
    Commented Mar 16, 2018 at 11:35
  • 1
    Here's one that has nothing to do with spaces, but rather with user defined structures in general: while it doesn't always bite you when you forget, it is best practice to close out numeric and dimensional specifications, as well as numeric and dimensional comparatives with \relax. Examples:\mylength=3pt\relax, \ifnum\x=3\relax...\fi. The same applies to closing out a \dimexpr and a \numexpr. Commented Mar 16, 2018 at 12:20
  • 1
    Another: you can't use ungrouped brackets [] 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. Commented Mar 16, 2018 at 12:30
  • 3
    @StevenB.Segletes beware that puts \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} Commented Mar 16, 2018 at 14:00
  • 1
    See also tex.stackexchange.com/q/34844/4427
    – egreg
    Commented Mar 16, 2018 at 17:56

4 Answers 4

7

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

enter image description here

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}

enter image description here

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}

enter image description here

6

Those "strange" formatting problems you mention are actually not strange at all, they are just a little tricky to see until one gets used to writing code in TeX.

The rules in this case are simple:

  • When TeX reads one or more spaces, it treats it as a single space.
  • When TeX reads one new line, it treats it as a space.
  • When TeX reads two or more new lines, it treats it as a paragraph break.

The tricky part here is that the % before the end of the line will "hide" the newline character from TeX. I gave a lengthier explanation of this here, if you have the patience.

An excellent reference for this is the TeXBook, of course. In particular, for how TeX reads the input, read the first 7 chapters. It's less than 50 pages of very useful information about how TeX works.

6

The reason for your "strange" formatting problems is that a single line break is equivalent to a space for TeX, i.e.

foo bar

is the same as

foo
bar

If you really want to typeset

foobar

but break the input into two lines for readibility (as you often should), you have to remove the linebreak by making it a comment:

foo%
bar

Note that spaces or tabs at the start of a line are always ignored, so you do not have to worry about indentation before bar.


As you probably know, macros gobble spaces following them. Accordingly, they also gobble the spaces produced by a newline in your input, i.e.

\foo bar

is the same as

\foo
bar

and there is no space typeset between the output of \foo and bar in either case.

In other cases where spaces are gobbled by TeX when reading the input (e.g. when reading numbers), the same rules also apply to single newlines.


As for recommendations: When defining macros, put a % before every newline that you do not explicitly want to be typeset as a space and that is not gobbled anyway. If you are unsure of the latter, put a % there to be on the safe side. It won't do any harm. (See below.)


As campa pointed out in his comment, in some cases a % at the end of a line may break your code, because TeX continues to read e.g. a number on the next line of code, that was supposed to end at the end of the line you commented with %. In these cases you can use \relax instead. (Although you should probably know exactly how TeX reads number assignments and tests anyway if you use those. If you don't, you should use the corresponding LaTeX macros instead.)

2
  • 1
    % is not always the safe choice. After numerical assignments or tests a % can cause lots of problems.
    – campa
    Commented Mar 16, 2018 at 11:48
  • @campa: You are absolutely right, Thanks for the hint.
    – schtandard
    Commented Mar 16, 2018 at 12:18
5

in order to avoid the subtleties of "invisible" commands that have a visible effect.

The main thing to remember is that TeX is primarily a typesetting system, not a programming language. By default, everything is supposed to have a visible effect: you type a+b into your .tex file and “a+b” comes out in the output; TeX does not try to do anything intelligent with your “variables”. TeX does have macros, but they are intended mainly as typing shortcuts: instead of typing similar stuff repeatedly, if you can identify a pattern, you can extract it out as a macro so that certain #1, #2 etc can be substituted into it.

The further you go from this mental model, the more unexpected problems you'll have. Conversely, one practice I've found very useful when defining “commands” (macros), “environments” (macros basically) etc., is to write out the expanded stuff first (the definition of the macro), debug it fully, and only later extract it into a macro. Similarly with newlines: first write everything on a single line, inserting spaces where you are sure they are fine, and then convert some spaces into line-breaks. (With practice you don't have to do either of these explicitly, but it's good to at least get into the habit of thinking that way.) I think this is the most general answer to your question:

do there exists general recommendations/practices to follow (or perhaps to comply with) when writing user defined commands, codes, etc. in order to avoid incurring in "strange" formatting problems?


Apart from this you need to know some stuff about how TeX deals with spaces (not specific to macros, because those are just expanded): after a control sequence it ignores spaces, when it gets into a “skipping blanks” state it skips ahead (e.g. treating consecutive spaces as 1), what TeX does when scanning for a number, etc. All these you can learn from The TeXbook or TeX by Topic.


Here are examples how this recommendation applies in the instances mentioned so far.

  1. The answer to your other question by @egreg: here, when you're writing the following as part of a \newcommand:

     \fbox{%
        \begin{minipage}[t]{\linewidth-2ex}
          #1
        \end{minipage}
      }
    

    it may seem natural to write that way, but when you put it on a single line, you'll notice that you've written something like \fbox{x } when instead you intend \fbox{x}. But if you had started writing it on a single line:

    \fbox{\begin{minipage} ... \end{minipage}}
    

    then probably you wouldn't have introduced any stray spaces in the first place. Then when you want to insert linebreaks, there's no space to convert to a linebreak. So the only thing you can do is pick a place and convert it to a % followed by a linebreak optionally followed by a number of spaces.


  1. The other answer you linked to: here, the user had written:

    \newcommand\quoteRefFormatAfter[3]{{
        \footnotesize
        \par\smallskip
        \hfill #1
        \par
        \hfill \quote*{#2} %
        \par
        \hfill{\scriptsize#3}% Problem !!!
    }}
    

    in which if the definition had been written first, and on a single line, it would have been

    { \footnotesize \par\smallskip \hfill #1 \par \hfill \quote*{#2} \par \hfill{\scriptsize#3}}
    

    where the problems are easier to see: the group begins with a space (which will be typeset, because remember TeX is primarily a typesetter), there are unwanted spaces before the \pars, etc. (Also in the original a line ended with a space followed by % which is useless.) So if we first change the line to only have spaces where acceptable:

    {\footnotesize \par\smallskip \hfill #1\par \hfill \quote*{#2}\par \hfill{\scriptsize#3}}
    

    then we can insert linebreaks by converting the spaces into linebreaks:

    {\footnotesize
     \par\smallskip 
     \hfill #1\par 
     \hfill \quote*{#2}\par
     \hfill{\scriptsize#3}}
    

    and now if we'd like more linebreaks, we have to resort to %:

    {%
     \footnotesize
     \par\smallskip 
     \hfill #1\par 
     \hfill \quote*{#2}\par
     \hfill{\scriptsize#3}%
    }
    

    and this we can stick as the definition of the command.


The other problem is also possible: if you leave out a space (including by putting % at the end of a line to ignore the linebreak), then TeX can continue looking for a number (or whatever) across the point where you could have inserted a space, which can lead to unexpected results.

See also @egreg's article and video (via) for some advanced examples.


Summary (repetition): TeX is a typesetter. Don't indiscriminately add spaces, (equivalently) linebreaks, or %s. All of them can be problematic. Instead: first write out everything in the expanded form carefully, with spaces wherever possible. (Anywhere a space is acceptable, put a space.) Then convert spaces to linebreaks per your preference, and convert non-spaces to linebreaks by using %.

0

Not the answer you're looking for? Browse other questions tagged .