# When do curly braces disappear in macro definitions? (e.g. \documentclass expansion)

I've been looking into how \documentclass and friends are actually defined, and I noticed something peculiar which I'd like to understand.

Let's say I have \documentclass[11pt, titlepage]{article}. From what I gather, \documentclass ultimately expands to \@fileswith@ptions\@clsextension, which is defined thus:

  \@ifnextchar[
{\@fileswith@pti@ns#1[{#2}]#3}%
{\@fileswith@pti@ns#1[{#2}]#3[]}}


I gather from that, that the optional parameters 11pt, titlepage are now put in braces. From simple experiments of the form \edef\foo{{{\bar}}}, it seems that those braces are not magically removed somehow, i.e. they seem to be preserved in further expansions, even when using \edef - i.e. from all I can gather the expansion is:

\@fileswith@pti@ns\@clsextension[{11pt,titlepage}]article[].

• First confusion: \@fileswith@pti@ns contains the line \xdef\@classoptionslist{\zap@space#2 \@empty}, which it seems to me is intended to remove the space between 11pt, and titlepage. But since \@fileswith@ptions put the optional parameters in braces, that shouldn't have any effect. In deed, trying \zap@space {a b} c \@empty yields a bc rather than abc.
• Furthermore, \@fileswith@pti@ns ultimately does \@onefilewithoptions#3[{#2}][{#4}]#1 - meaning it puts an additional pair of braces around the optional parameters, yielding

\@onefilewithoptions article[{{11pt, titlepage}}][{}]\@clsextension. So now we have two spurious pairs of braces around the package parameters.

But all the further processing of the parameters is (ultimately) based on for-loops and \@ins, which split at commas (using parameter strings with comma-delimiters). So it seems to me that the braces that are introduced by \@fileswith@ptions and \@fileswith@pti@ns have to either be removed somewhere, or in some places they are ignored...? Can someone explain TeXs magic behavior here?

TeX drops the braces from a macro argument if the entire argument is in a brace group so in

\frac{1}{2}

#1 is 1 not {1}

But this also applies to delimited arguments after

\def\foo[#1]#2{....}

then in \foo[{abc}]{xyz} #1 is abc and #2 is xyz both brace groups are dropped.

the code you quote does [{#2}] in case #2 contains a ] in which case the delimited argument matching would fail, but the braces surround the entire argument so are never passed on to the macro being called.