8

I'm interested in a macro \nullifyifmoved that takes one argument arg and acts like arg in normal contexts, except it acts like a no-op wherever it is written to a file. Some background:

Martin Scharrer writes in some comment to another question:

A moving argument is an argument which is written into an auxiliary file (like .aux, but also .toc and others) which is then read on some other position at the next run. Things like sectioning titles and labels are moving arguments.

This is an excellent explanation of the technical term "moving argument". Recall that macros can be "expanded" or "executed"; \protect prevents expansion. I want something converse, that doesn't prevent expansion but in fact deletes that instance of the macro entirely whenever it is being written to a file (i.e. wherever the argument is "moved").

There are two other questions that are related (but not identical):

  • 2
    Have a look at http://tex.stackexchange.com/questions/98808/why-is-thepage-set-to-relax-in-a-protectedwrite – yannisl Feb 23 '13 at 23:05

2 Answers2

13

All writing operations in LaTeX use the command \protected@write; in Why is \thepage set to \relax in a \protected@write? one can find something about it, in particular the fact that it sets \thepage to relax before doing the primitive operation \write, in order to avoid untimely expansion. This \let operation is performed in a group.

The idea for your problem is just the same: we define \nullifyifmoved to \@gobble in that group so that its argument is completely ignored; its normal definition will be the same of \@firstofone, which simply returns its argument.

Instead of redefining \protected@write we can append \let\nullifyifmoved\@gobble after \let\thepage\relax with

\usepackage{etoolbox}
\makeatletter
\patchcmd{\protected@write}
  {\relax}
  {\relax\let\nullifyifmoved\@gobble}
  {}{\@latex@error{Could not patch \string\protected@write}}
\@ifdefinable{\nullifyifmoved}{\let\nullifyifmoved\@firstofone}
\makeatother
egreg
  • 1,121,712
8

rather than locally switch the definition of \nullifyifmoved in moving contexts you can probably give it a global definition of

\def\nullifyifmoved{%
   \ifx\protect\@typeset@protect\else\expandafter\@gobble\fi}

so that in a context where \protect is doing anything fancy the command gobbles the following token, otherwise it expands to nothing.

For example, with the following code

\documentclass{memoir}

\makeatletter
\def\nullifyifmoved{\ifx\protect\@typeset@protect\else\expandafter\@gobble\fi}
\makeatother

\begin{document}

\tableofcontents

\section{Hello\nullifyifmoved{\footnote{This is a footnote}}\nullifyifmoved{, goodbye}}

Text.

\end{document}

the section heading is Hello¹, goodbye in the document body but only Hello in the table of contents.

David Carlisle
  • 757,742
  • (David Carlisle and egreg:) Are your answers substantially equivalent? (From your respective solution writeups: Are "a place 'where \protect is doing anything fancy'", "a moving context", and "a context where \protected@write is used" equivalent?) – Lover of Structure Mar 03 '13 at 02:44
  • No protected@write is one class of moving argument but there are others, protected@edef for example or \PackageInfo tabular preamble constructs such as @{...} etc. – David Carlisle Mar 03 '13 at 10:07
  • To others: Please see also user egreg's excellent answer. – Lover of Structure Mar 04 '13 at 00:42