8

Which of the following declarations is preferred when defining new textual macro's in latex

\newcommand*{\dosomething}[1]{\textbf{#1}}

versus

\newcommand*{\dosomething}{\textbf}

textbf is just used as an example. I know that the latter construction is not allowed if used inside a group e.g.

\newcommand*{\dosomething}{\begingroup\textbf\endgroup}

Are there other issues with one of these macro declarations?

  • Yes and no... none of them allows long arguments, i.e. a (implicit or explicit) \par inside the argument. If this is not an issue, than the 1st version is 'alright', the second one should be used with extreme care... and you stated already, that it's not possible to use 2nd version in a group –  Jan 05 '15 at 00:50

3 Answers3

9

The form

\newcommand*{\dosomething}[1]{\textbf{#1}}

is slightly slower than

\newcommand*{\dosomething}{\textbf}

because with the first form the argument is read in just to be fed again to \textbf.

On the other hand, the first form is much clearer, because it shows the intended meaning. It's also better if you plan to modify it later on, but this is not really relevant.

When TeX finds a macro, it knows how many arguments it's defined with, so it looks for them and proceeds to replace the tokens with the macro's replacement text.

So, with the second form, \dosomething{xyz} would make TeX replace \dosomething with \textbf and go on, finding the argument to \textbf.

With the first form, \dosomething{xyz} will be replaced by \textbf{xyz} and TeX would look again for the argument of \textbf; this explains why the first form is slower (a few nanoseconds, perhaps).

Note that the third form is incorrect, because \endgroup would be fed as the argument to \textbf, which is not a desirable thing to do.

Going to the facetious side, using the second form is a sign of being either a macho or a cargo cult LaTeX programmer. What category, the rest of the code will tell.


Another possibility is available, but it has several disadvantages:

\let\dosomething\textbf

Problem 1. It's not documented in the LaTeX manual and, differently from \newcommand, it doesn't check whether \dosomething already has a definition.

Problem 2. If you change the meaning of \textbf (say that your inhouse style requires that boldface should always be upright), then it would matter if the change to \textbf is made before or after the \let instruction. Of course this may be considered as a silly example, but it gives the idea.

Indeed, \let freezes the meaning of the second token, in the sense that the first token (in this case \dosomething) assumes the current meaning of the second token (in this case \textbf). Later changes in the meaning of the second token wouldn't be reflected in the first token. This doesn't happen with either \newcommand strategy above.

The \let command has its uses, but it should appear very rarely in a document preamble, usually in the form \let\foo\relax for special purposes involving the redefinition of \foo.

Problem 3. In any case, without a rather deep knowledge of how LaTeX macros work, it's not advisable to use \let, in particular for modifying the behavior of a macro keeping its current meaning (see the documentation of the letltxmacro package for more information.

egreg
  • 1,121,712
5

As egreg notes it's generally clearer to use the first form (but only use * if you intend to remove the possibility of a blank line in the argument)

That said, it's really a matter of choice of coding style and latex internally uses the second form all over the place. \textbf itself for example does not take an argument as you can see with \show.

*\show\textbf
> \textbf=macro:
->\protect \textbf  .
<*> \show\textbf

\textbf expands without taking an argument to the two tokens |\protect| and |\textbf | (note the space) and it is the latter command that actually has a #1 argument.

David Carlisle
  • 757,742
4

If we needn't the name checking of the defined control sequence then your
question can be reformulated by \def and \let primitives:

There are three possibilities how to define textual macro:

  1. \def\dosomething#1{\textbf{#1}}
  2. \def\dosomething{\textbf}
  3. \let\dosomething=\textbf

I prefer the third one if it is possible, i. e. if the new sequence would
take the meaning of one known "static" sequence. Of course, the second and third variants are not the same: if somebody changes the meaning of
\textbf after \def or \let \dosomething, then \dosomething keeps
its original meaning if \let was used, but it changes the meaning if \def was used.

If I need to replace one token to more tokens then I am using first or second alternative; second is preferred, if it is possible. For example:

\def\mbox{\leavevmode\hbox}

This keeps the special parameter scanning used by the primitive \hbox and keeps the catcode changing inside the parameter. For example, user can write not only \mbox{...} but also \mbox to2em{...}. On the other hand, LaTeX kernel defines

\long\def\mbox#1{\leavevmode\hbox{#1}}

so you cannot do \mbox to2em{...} and you cannot do catcode changes inside the parameter.

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036
wipet
  • 74,238
  • Note getting an error message from the syntax error \mbox to2em is the main reason that latex defines \mbox the way it does. If you redefine \mbox you lose that. The correct syntax is \makebox[2em]{...} – David Carlisle Jan 05 '15 at 12:00
  • while your comment that \something keeps its meaning if \let is used can be interpreted as technically correct, it's a bit misleading as the observable behaviour would almost certainly change. with \let \something is defined to be <\protect\textbf > so if \textbf is redefined then most likely the internal version would also be redefined, and \something would use the new definition even when defined via \let. – David Carlisle Jan 05 '15 at 12:04
  • @DavidCarlisle You don't get an error with \mbox to2em in LaTeX. Perhaps you meant more 'LaTeX's defined syntax convention is that optional arguments are always in square brackets: TeX primitive optional keyword arguments are deliberately screened out' or something like that? – Joseph Wright Jan 05 '15 at 13:11
  • @JosephWright hmm I suppose not, but it just boxes the t and the o2em does whatever it does. As you say, it probably doesn't generate an error in most circumstances. However it not affecting the size of the box is a good feature. – David Carlisle Jan 05 '15 at 13:13