104

I'm trying to work through LaTeX Beginner's Guide by Stefan Kottwitz. Here's where I got stumped:

\documentclass{article}
\newcommand{\keyword}[2][\bfseries]{{#1#2}}
\begin{document}
\keyword{Grouping} by curly braces limits the
\keyword{scope} of \keyword[\itshape]{declarations}.
\end{document}

The output adds boldface to "Groupings" and "scope," while "declarations" is italicized. I do not understand this syntax. I vaguely get that \bfseries is the "default" and \itshape got specifically subbed in for "declarations" but I cannot follow Kottwitz's explanation:

Let's look again at the bold marked line in the code. By using [\bfseries], we introduced an optional parameter. We refer to it with #1. Its default value is \bfseries. Since we used a declaration this time, we added a pair of braces to ensure that only the keyword is affected by the declaration. Later in the document, we gave [\itshape] to \keyword, changing the default formatting to italics.

Can I get a second opinion/explanation of what is going on here?

2
  • 2
    Welcome to TeX.SE. The additional pair of braces was need to introduce a group so that any switch type macro passed in as the optional #1 had it's effect limited to be within the text (#2) of this macro. Jun 3, 2013 at 2:48
  • 1
    I'm reading the same book at this very moment. One thing Stefan did not include was how to specify multiple mandatory arguments when calling the command (\mycommand{mandatory_arg1}{mandatory_arg2}). Jul 6, 2017 at 18:38

4 Answers 4

165

The syntax of \newcommand without an optional argument is the following:

\newcommand{<name>}[<args>]{ <code> }

Where <args> is the number of arguments (ranges from 1-9). Within the <code> part of the definition, each of the arguments is marked with a # sign: so the first argument is #1 the second is #2 etc. So if we create a macro \reverseconcat which has three obligatory arguments and concatenates them in reverse order, we would define it as follows:

\newcommand{\reverseconcat}[3]{#3#2#1} % version 1

And we would use it as follows:

\reverseconcat{A}{B}{C}

which would output "CBA"

Now suppose we wanted our command to make the output bold. To do this we want to add \bfseries in our code. Suppose we did this:

\newcommand{\reverseconcat}[3]{\bfseries#3#2#1} % version 2

If we pass the same arguments to this command however, we run into a problem: the code part acts as if we just typed \bfseries CBA in our document, and since \bfseries is a switch, it will make all following text bold, which is not what we want. So in this case, we need to limit the scope of the \bfseries by adding braces around the code part.

\newcommand{\reverseconcat}[3]{{\bfseries#3#2#1}} % version 3

Now when we pass the same arguments to this command it's as if we typed {\bfseries CBA} in our document, which is what we want.

Now suppose we want our command to have an optional argument. By definition, the optional argument is always the argument designated #1 (i.e. the first argument). However, since the command still has a first argument even if it's left out by the user, we still need to provide a value for it. So the syntax of the command changes:

\newcommand{<name>}[<args>][<first argument value>]{<code>} 

Now let's make our reverse concatenation macro take an optional argument that specifies how to format the reversed text. In this case, our new macro will then take four arguments (assuming we still want the 3 arguments we originally had.)

So our new command looks like this:

\newcommand{\reverseconcat}[4][\bfseries]{{#1#4#3#2}}

This macro will behave exactly like version 3 above, so \reverseconcat{A}{B}{C} will output "CBA". Notice, however, that because we've added the optional argument, the numbers used for the reversing part are different: they start at #2 because #1 is the optional argument.

Our new command, however, allows us to specify a different value for the first argument, however, so if we don't want the text to be bold, we can pass \itshape to make it italic:

\reverseconcat[\itshape]{A}{B}{C}

and this will produce "CBA"

As Przemysław Scherwentke says in his answer, you could actually pass anything to this command, not just a formatting command, so if, for example, you forgot the \ on \itshape:

\reverseconcat[itshape]{A}{B}{C}

The output would be "itshapeCBA"

This last example shows that expecting the user to pass a command to another command probably isn't the best idea, since you'd like the example above to produce an error rather than produce incorrect output. But solving that problem here would take us too far afield.

5
  • 11
    Off topic. In Poland it is 6 o'clock now. CBA (Centralne Biuro Antykorupcyjne) is an organization like FBI. Typical time of their action is 6 o'clock. :-) Alas, I cannot additionaly upvote conotations. Jun 3, 2013 at 4:10
  • 1
    what about multiple optional arguments ?
    – Welgriv
    Oct 20, 2021 at 12:37
  • 1
    @Welgriv Multiple optional arguments are not possible using \newcommand syntax. You can use the xparse syntax \NewDocumentCommand to achieve this however. See e.g. xparse: Define new command with multiple optional parameters. But depending on the use case it might be better to use a key-value syntax instead.
    – Alan Munn
    Oct 20, 2021 at 13:40
  • @AlanMunn Could you add an example of the key-value syntax?
    – Andyc
    Feb 17, 2022 at 16:54
  • @Andyc I don't think adding a key-value example would be helpful to this particular question, which answers a relatively elementary question that can be helpful to many new LaTeX users. There are plenty of key-value examples on the site. See e.g. Simple key-value example, newcommand key value, and How to create a command with key values? and for package options key-value syntax in package options.
    – Alan Munn
    Feb 17, 2022 at 22:58
56

There are two separate things happening here, and I think perhaps tackling them simultaneously is creating confusion. The first thing is optional arguments and the second thing is braces for scoping.

Optional arguments

When you define a command

\newcommand\isgreat[2]{#1 thinks #2 is great.}

you put { and } around the definition. Then occurrences of \isgreat are replaced as you'd expect:

\isgreat{John}{Stack Exchange} He uses it every day.

John thinks Stack Exchange is great. He uses it every day.

If you had written this instead:

\newcommand\isgreat[2][John]{#1 thinks #2 is great.}

then the first argument is optional. If you don't give it, it defaults to John

\isgreat{LaTeX}

John thinks LaTeX is great.

and if you do give it, you have to put it in square brackets.

\isgreat[Gary]{LaTeX}

Gary thinks LaTeX is great.

Braces for scoping

When you write \bfseries, that's like clicking the "Bold" toolbar button in Microsoft Word -- everything you type from then on will be bold.

John thinks LaTeX is \bfseries great. He uses it every day.

John thinks LaTeX is great. He uses it every day.

In order to restrict the boldness to a specific part of the text, you can enclose it in braces.

John thinks LaTeX is {\bfseries great}. He uses it every day.

John thinks LaTeX is great. He uses it every day.

Finally

In Stefan's example, LaTeX replaces

\keyword{Grouping} by curly braces

with

{\bfseries Grouping} by curly braces

Do you see why the extra curly braces in the \newcommand are needed? One pair is needed to provide the definition, and one pair to restrict the scope of the \bfseries command.

13

\newcommand{\keyword}[2][\bfseries]{{#1#2}} is a macro with 2 parameters and an optional argument. If it is not specified, \bfseries is taken as the first argument. If you write, e.g., \keyword[AAA]{declarations}, you will obtain AAAdeclarations in the roman font.

2
  • 1
    So the first parameter is either the default [\bfseries] or whatever you may add to override the default, the second parameter is the word or phrase you want to apply this all to. The book's previous example, \newcommand{\keyword}[1]{\textbf{#1}}, can only make the word or phrase boldface.
    – 147pm
    Jun 3, 2013 at 3:49
  • @user78162 Yes, exactly! Jun 3, 2013 at 3:58
2

I think the puzzling part, as pointed out profusely in John's answer, is that the sentence

Since we used a declaration this time, we added a pair of braces to ensure that only the keyword is affected by the declaration.

refers declaration which may be confused with something related to the declaration of a new command.

Instead, it refers to the fact that the expansion of \newcommand contents will not be automatically scoped, and in the specific case of using \bfseries and other declarations, you will have to take car of the scoping youself, by letting the last argument of newcommand be scoped: {#1#2} rather than #1#2

maybe starting with a different example helps:

\documentclass{article}
\newcommand{\dummy}[2][0]{#2^#1}
\begin{document}

the default is $\dummy{A}$ but you can switch to $\dummy[2]{A}$

\end{document}

You must log in to answer this question.

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