[Tex/LaTex] \newcommand argument confusion

macros

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?

Best Answer

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.

Related Question