8

When defining macros using \edef (which by default expands every macro within the definition as much as possible), I can declare some macro within that definition to not expand by using \noexpand before that macro. So \noexpand could be seen as declaring an exception to the default behavior of expanding everything.

However, sometimes I only want very few commands to be expanded. Now when I define a macro using \def, the default behavior is to not expand anything within the definition (at the point of the definition - it may of course later be expanded after the new macro has been expanded somewhere). Is there a command for manually expanding a macro (fully or just one step) at the point of definition when defining it using \def or any other definition command such that normally macros are not expanded (in analogy to declaring an exception as with \noexpand within \edef)? If so, what is the command and its exact effect?

To illustrate the question by an example, I can have the following code using \edef:

\documentclass{article}

\newcounter{mycount}

\edef\foo{\noexpand\textit{\arabic{mycount}}}

\stepcounter{mycount}

\begin{document}

Before: \foo

After: \arabic{mycount}

\end{document}

The output is:

Before: 0
After: 1

My question is whether there is a command \doexpand (or whether such a command could be defined) such that the following code would yield the same result:

\documentclass{article}

\newcounter{mycount}

\def\foo{\textit{\doexpand\arabic{mycount}}}

\stepcounter{mycount}

\begin{document}

Before: \foo

After: \arabic{mycount}

\end{document}

EDIT: Some alteration of the last code would be ok. My restriction is not to use \def but to have any way of defining a macro such that macros within that definition are normally not expanded as long as they are not "marked" somehow to be expanded.

6
  • When TeX absorbs the replacement text for \def it performs no expansion.
    – egreg
    Dec 19, 2015 at 23:10
  • Does that mean the answer to the question is simply "no"? Maybe I can broaden the question a little bit: Is there a way to achieve a definition where I only declare which commands are to be expanded instead of declaring which should not be expanded? Dec 19, 2015 at 23:13
  • Since nothing is expanded, any macro \doexpand would also be not-expanded. Only if it was first expanded would TeX know that the following command should also be expanded. But that would mean you would need to ensure that \doexpand was expanded, so you'd need \doexpand\doexpand. But now the problem is that TeX can only know that \doexpand means to expand the next thing if it first expands \doexpand. So we need to ensure that \doexpand is expanded, too. That is, we need \doexpand\doexpand\doexpand ...
    – cfr
    Dec 19, 2015 at 23:32
  • Why don't you use the first code if you want code which produces the same result?
    – cfr
    Dec 19, 2015 at 23:37
  • @cfr The reason is simply shorter code. If I want do define a complicated macro that uses a counter like in the example above and I only want the counter to be expanded but nothing else, then I would like to just write some \doexpand in front of the counter use instead of writing \noexpand everywhere else. Dec 20, 2015 at 0:09

2 Answers 2

9

When TeX absorbs the replacement text of a macro for \def it performs no expansion whatsoever. To the contrary, when it does \edef it expands every expandable token recursively, with some exceptions.

The exception is that tokens resulting from the expansion of \the<token register> are not expanded further. The same for tokens resulting from \unexpanded, that's very similar to using an unnamed token register. The expansion of \noexpand is empty, but it makes the next token temporarily equivalent to \relax, so it's not expanded further.

This seems to exclude the possibility of doing \doexpand. However you can use regular expressions: change every control sequence <cs> into \noexpand<cs> and then change \noexpand\doexpand\noexpand into nothing.

There are several limitations in the following implementation of \pedef (partial \edef): \doexpand must precede a control sequence and active characters are not covered; also parameters to the macro are not allowed, so it's just a proof of concept.

\documentclass{article}
\usepackage{xparse,l3regex}

\newcounter{mycount}
\setcounter{mycount}{42}

\ExplSyntaxOn
\cs_new_protected:Npn \pedef #1 #2
 {
  \tl_set:Nn \l_tmpa_tl { #2 }
  \regex_replace_all:nnN { (\cC.) } { \c{noexpand}\1 } \l_tmpa_tl
  \regex_replace_all:nnN { \c{noexpand}\c{doexpand}\c{noexpand} } { } \l_tmpa_tl
  \cs_set:Npx #1 {\l_tmpa_tl}
 }
\ExplSyntaxOff

\pedef\foo{\textit{\doexpand\arabic{mycount}}}

\show\foo

This outputs

> \foo=\long macro:
->\textit {42}.
3
  • I don't understand that \doexpand must precede a control sequence. Is \textit no control sequence? Dec 20, 2015 at 0:13
  • 1
    @cryingshadow \doexpand must precede the control sequence you want to be expanded. I used must because \noexpand can precede any token.
    – egreg
    Dec 20, 2015 at 0:15
  • Loading l3regex is no longer required.
    – egreg
    Oct 7, 2018 at 14:16
2

For the specific case of a counter, you could do something like this. The idea is to create a macro \savebefore{<counter>} which saves the value of the counter. This can be used at any point e.g. you can save the value at one point and then later save the new value, overwriting the existing one. \excounter<command>{<counter>} then uses the saved value, rather than the current value, if available, or the current value, if not.

A test from etoolbox is used to check whether the counter exists or not.

MWE:

\documentclass{article}
\usepackage{etoolbox}
\makeatletter
\newcommand*\savebefore[1]{%
  \ifltxcounter{before@#1}{}{\newcounter{before@#1}}%
  \setcounter{before@#1}{\value{#1}}%
}
\def\excounter#1#2{%
  \ifltxcounter{before@#2}{%
    #1{before@#2}%
  }{%
    \typeout{No prior value for counter saved. Using current value.}%
    #1{#2}%
  }%
}
\makeatother

\newcounter{mycount}
\savebefore{mycount}% save current value

\def\foo{\textit{\excounter\arabic{mycount}}}% command defined to use saved value

\stepcounter{mycount}% change value

\begin{document}

Before: \foo

After: \arabic{mycount}

\end{document}

Although less general than \doexpand, this offers greater flexibility in certain ways because the saved value is not frozen in the command \foo. Rather \foo always prints the last saved value (the 'current before' value, if you like).

For example, sticking with \foo:

Before: \foo

After: \arabic{mycount}

\savebefore{mycount}

Before: \foo

\addtocounter{mycount}{5}

After: \arabic{mycount}

produces

saving and changing

Or you can say something like this

\newcommand\footoo[1]{%
  Before: \excounter\arabic{#1}\par
  After: \arabic{#1}\par
}

And then use

\footoo{mycount}

to produce

foo too

You must log in to answer this question.

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