Don't confuse \protect with \protected.
The latter is a primitive prefix for \def \gdef \edef \xdef and announces TeX that the defined control sequence (or active character) should behave in e-expansion or x-expansion as if it were prefixed by \noexpand.
e-expansion is used in the replacement text passed to \edef or \xdef and in the argument to \expanded or \write.
For instance,
\def\AAA{xyz}
\expanded{\noexpand\AAA}
\protected\def\BBB{xyz}
\expanded{\BBB}
would produce \AAA and \BBB respectively; macro expansion will take place later, following the usual rules.
Why is \protected important? The above silly examples don't tell us. Suppose you want to write some text out to an auxiliary file to be \input later. In the text you want to write out there is the control sequence \foo that you don't want to be expanded when \write is carried out, but only when you \input the file.
The traditional way would be
\def\foo{}% initialize
\newwrite\outstream=myauxfile
\begingroup\let\foo\relax
\write\outstream{some text with \foo}
\endgroup
\def\foo{Useful definition}
\input myauxfile
which works because \relax is unexpandable and so \foo will be written out as \foo. You need no \let if you do instead
\protected\def\foo{}% initialize
\newwrite\outstream=myauxfile
\write\outstream{some text with \foo}
\endgroup
\def\foo{Useful definition}
\input myauxfile
(maybe again using \protected when you redefine \foo, depending on the actual job you want to do).
To the contrary, \protect is not a primitive. It's a control sequence whose meaning changes depending on the context. In the earliest version of LaTeX you could find
\def\LaTeX{\protect\pLaTeX}
\def\pLaTeX{<the actual code for the logo>}
So if \LaTeX was found during typesetting, \protect would do nothing. But when \LaTeX was found in the argument to \protected@edef or \protected@write (wrappers for \edef and \write), the meaning of \protect would change to \noexpand (this is the basic idea, the actual implementation is a bit more complex) and so when the underlying \edef or \write commands are executed, \pLaTeX would remain.
Nowadays there is no explicit double definition with the p prefix, but the idea remains the same. Robusted commands are defined with \DeclareRobustCommand so that
\DeclareRobustCommand{\foo}{something}
is the same as
\expandafter\def\expandafter\foo\expandafter{%
\expandafter\protect\csname foo \endcsname
}
\expandafter\def\csname foo \endcsname{something}
so instead of \pfoo like in the older way, a command \foo (with a trailing space in the name) is defined. This way, the written out file would show \foo (with two spaces), but this is unimportant when the file is \input.
How does f-expansion work? It exploits a slick feature of TeX (that can bite if you're not careful): when TeX is looking for an explicit <number>, it performs macro expansion until finding a space token or an unexpandable token that cannot be interpreted as providing a <number> under the current radix. The radix can be 10, 8, 16 or “alphabetic”. The rules are not difficult:
- an explicit number can begin with any number of
- or + tokens
- a radix designation may follow and can be a backquote
`, a straight quote ' or a double straight quote "
- no radix designation means base ten
- the straight quote and the double straight quote mean octal and hexadecimal respectively
- the backquote means “alphabetical” constant
- digits, depending on the specified radix
An alphabetic constant is either a single character token or a control sequence of length one, such as \Q. The trick used by f-expansion is that macro expansion is done also after an alphabetic constant and the idea is that
\romannumeral-`\Q\foo
will expand \foo before typesetting the result of \romannumeral-`\Q (which is empty because the <number> is negative). However, when doing this, the status of \foo with respect to \protected is ignored. Thus, using expl3 lingo, the following will produce different results:
\cs_new_protected:Nn \aad_foo: {abc}
\cs_new_protected:Nx \aad_foo_a: { \aad_foo: }
\exp_args:NNf \cs_new_protected:Nn \aad_foo_b: { \aad_foo: }
Indeed, if you try \cs_show:N \aad_foo_a: and \cs_show:N \aad_foo_b:` you will get respectively
> \aad_foo_a:=\protected\long macro:->\aad_foo: .
> \aad_foo_b:=\protected\long macro:->abc.
The similar situation is in c-expansion, when TeX is trying to build a control sequence via \csname. In this case it's obvious to ignore \protected, because only character tokens should remain. Maybe the authors of e-TeX could have decided that in the context of c-expansion a \protected macro would get prefixed by \string; they didn't.
\protected– David Carlisle Jan 01 '23 at 10:35expl3. If this were a reasonable justification, you could simply forego the entireexpl3project, and say of the various TeX primitives: "This behavior is as specified in the TeX book". – Evan Aad Jan 01 '23 at 10:37candfis pretty weird anyway and largely replaced byenow the tex engines have been extended with an\expandedprimitive. – David Carlisle Jan 01 '23 at 10:43expl3programming language, and for hard to debug programs. – Evan Aad Jan 01 '23 at 10:47\protectedmean in ac-type expansion? Simply leaving macro names there doesn't really 'work'. For active chars, we are moving toward a setup that uses\ifincsnameto produce 'the char itself' in those contexts, but that's done in the definitions of the actives (and therefore is not dependent onexpl3-specific code) – Joseph Wright Jan 01 '23 at 11:15