[Tex/LaTex] On unprotecting (expanding) \protected macros (or, “the space after command name”)

debuggingexpansionmacrostex-core

I quite often come into a situation, where I need to obtain some text produced by a package macro as a string, like in say:

One thing I bump into here, is trying to \typeout the macros in question, and typically observing a space between the \command and its arguments (hence the title); and I'd usually take this wrongly as a string parsing problem (as in, how do I remove the space between the command and its arguments), and spend quite a bit of time in a pointless battle :)


EDIT: to clarify this:

  • In the 1st link: \lipsum[1] command typesets "Lorem Ipsum…" in the PDF document; one would want to somehow obtain the characters for "Lorem Ipsum…" in a \temp command, such that \typeout{\temp} would print "Lorem Ipsum …" to the terminal and log output.
  • In the 2nd link: \today from isodate typesets "24 May, 2012" in the PDF document; likewise, one would want to somehow obtain the characters for "24 May, 2012" in a \temp command, such that \typeout{\temp} would print "24 May, 2012" to the terminal and log output.

(whether \edef is used for the purpose is not that much of an issue, I guess; but as far as I can see, it is the only command possibly appropriate)


Now, I finally came up with an MWE that demonstrates this, so I'd like to ask about this in more generic terms – consider:

\documentclass{minimal}

\def\doubleCommand#1#2{testing-#1-#2}

\protected\def\tmpcmd#1{teststring#1} % concatenate, no spaces


\begin{document}

\typeout{--Test:--\doubleCommand{A}{B}--}

\edef\initArg{12}
\edef\dcArg{\tmpcmd\initArg}

\typeout{--Args:--\initArg--\dcArg--}

\edef\myResult{\doubleCommand{\dcArg}{Verbatim}}
\edef\myResult{\detokenize\expandafter{\myResult}}

\typeout{--Out :--\myResult--}

This: \doubleCommand{\dcArg}{Verbatim}

\end{document}

Now, this works fine, and typesets "This: testing-teststring12-Verbatim", as expected. However, if we look at the terminal log output from pdflatex, we get:

--Test:--testing-A-B--
--Args:--12--\tmpcmd 12--
--Out :--testing-\tmpcmd 12-Verbatim--

That is, the \edef didn't expand the \tmpcmd command – and its name is printed instead, along with the arguments (and notably, there is the space between the command and the first argument :)).

However, since the content is typeset fine, it is obviously accesible somewhere – and it is this content that I would like to have as a "string" in a variable. To show this, all I need to do is remove the \protected command, so I have:

\def\tmpcmd#1{teststring#1} % concatenate, no spaces 

… and then the terminal log shows:

--Test:--testing-A-B--
--Args:--12--teststring12--
--Out :--testing-teststring12-Verbatim--

… that is, the command output ("teststring12-Verbatim") is now a "string" value in a "variable" (command).

Now, I'm pretty sure there are good reasons for \protected; however, many times I just want to get to the data which is typeset anyways. So is there a strategy that one could employ in these cases? The above links suggest there is not, and a solution – if possible – depends on a given package's command, and its implementation… However, I'd like a method that I could employ, without changing package style files (like, say, removing \protected from diverse macros I might need, which even without further knowledge, I can tell is a bad idea).

I can already guess such a general method is not available – but could anyone explain why (maybe in terms of the above MWE)?

Many thanks in advance for any answers,
Cheers!

Best Answer

David has explained this one way, I will take a slightly different tack.

First, what is going on? When e-TeX finds a protected macro, it will not expand it inside an \edef, \write and some similar circumstances, which usually exhaustively expand everything. That is to ensure you can see the protected token in the result. For example,

\protected\def\a{}
\typeout{%
  \a%
  b%
}

will show \a b, even though there is no space between \a and b as far as TeX is concerned. That's because the alternative is \ab, which as we can't see the tokens would be misleading (does it mean \a followed by b or a different macro \ab?).

You can 'force' expansion of a protected macro by using the fact that they do respect \expandafter:

\protected\def\a{b}
\edef\test{\expandafter\empty\a}
\show\a

using \empty as something to expand after which will not result in anything remaining behind.

Second, why do you need protection? Some operations in TeX simply will not work within an \edef as they use TeX primitives which are not 'expandable'. The classic ones here are assignments (\def, \let and so on). If you try

\let\a\undefined
\def\b{a}
\edef\test{\let\a\b}

you will not find that \a ends up defined to give a. Instead, you'll get an error: in this case 'Undefined control sequence'. That is because \let is not expandable. So TeX simply 'leaves it alone' inside the \edef, and tries to expand \a. That's not possible, and so an error arises. Thus in general it is not a good idea to try to expand protected macros.

Related Question