[Tex/LaTex] How to make a command completely empty / invisible / non-existent

macrosspacing

I have a command like

\newcommand{\todo}[1]{#1}

which I sometimes replace by:

\newcommand{\todo}[1]{}

In terms of spacing/whitespace, the behavior of the "empty" command is as follows:

Test.

\todo{foo} % does not generate (vertical) whitespace => good

Test\todo{foo}. Test. % does not generate (horizontal) whitespace => good

Test\todo{foo}. \todo{foo} Test. % _does_ generate (horizontal) whitespace => bad

Is there any way to avoid this, i.e., to (temporarily) replace a command in a way so that it is fully equivalent to removing all occurrences of the command?

(I know that there are packages like todonotes or verbatim, which provide similar functionality. But I always wanted to know how to solve this manually, and never had an idea how to approach this / what to search for. Using \xspace or \empty in the command did not work at least.)

Best Answer

The classical way is using \@bsphack and \@esphack. They are used by \label or \index, both supposed to be invisible/empty regarding spacing. These commands remember, if there is a space before the command. If yes, the second space afterwards is suppressed by \ignorespaces. The commands are defined in the LaTeX kernel:

\def\@bsphack{%
  \relax
  \ifhmode
    \@savsk\lastskip
    \@savsf\spacefactor
  \fi}
\def\@esphack{%
  \relax
  \ifhmode
    \spacefactor\@savsf
    \ifdim\@savsk>\z@
      \ignorespaces
    \fi
  \fi}

Applied to \todo:

\documentclass{article}

\makeatletter
\newcommand{\todo}[1]{%
  \@bsphack
  \@esphack
}
\makeatother

\begin{document}
Test.

\todo{foo}

Test\todo{foo}. Test.

Test\todo{foo}. \todo{foo} Test.
\end{document}

Result

Limitation: The method can fail, if the macros using \@bsphack and \@esphack are used one after each other. The second \@bsphack does not know the state of the previous one. Therefore \ignorespaces can be suppressed leaving the following space.

Related Question