I am using the article
class, and I discovered that the tocloft
package defines \chapter
, which will mess up with my other stuff. How does this happen? Can I make \chapter
"undefined" again after loading tocloft
? Here is an MWE:
\documentclass{article}
% loading tocloft will make \chapter defined
\usepackage{tocloft}
\begin{document}
\ifdefined\chapter
chapter is defined in the current \texttt{article} document.
\chapter{This is not a chapter, but will be typeset as plain text}
\else
chapter is \emph{not} defined.
\fi
\end{document}
Best Answer
Some packages and macros check whether
\chapter
is defined or not in order to take some action; for example, to typeset the bibliography as a chapter (book
andreport
classes) or as a section (article
class).The test they perform is based on
\@ifundefined
, something likeIt's important to know that
\@ifundefined
returns true when the command given in the argument by its name is undefined or equivalent to\relax
. Actually, whenever one usesthe command
\foo
will become equivalent to\relax
if it weren't defined before.Conversely, the
\ifdefined
conditional returns true also when the token after it is equivalent to\relax
and this is why you observe this behavior: indeedtocloft
checks for the existence of\chapter
with\@ifundefined
.The reason for this is historical: LaTeX needs to know whether
\foo
is defined or not when\newenvironment{foo}
is issued, or\c@foo
for\newcounter{foo}
. So the macro\@ifundefined
takes as argument the name, rather than the token itself. It uses internally\csname...\endcsname
which has the effect outlined before: if\foo
is undefined, then using\csname foo\encsname
will let it to be equivalent to\relax
.There should be no problem as long as you stick to
\@ifundefined
to test for definedness.The
\ifdefined
and\ifcsname
primitives are e-TeX extensions, so they were not available when LaTeX2e was released. There was really no other reliable way to check for definedness; a different strategy would have been to compare with an undefined token (there is\@undefined
for this). However, the\csname...\endcsname
problem would remain, unless one uses a slick trick:so that
\@ifundefined{foo}
wouldn't leave\foo
equivalent to\relax
if it wasn't defined. However this test is not completely expandable because of\begingroup
and\endgroup
, so the developers decided to leave\@ifundefined
as it was.The trick works because
\csname foo\endcsname
is performed before TeX scans the\endgroup
and so the equivalence with\relax
vanishes as soon as TeX executes it; but the conditional\ifx
has already been expanded. :)Note that in LaTeX releases from 2018 onwards the definition of
\@ifundefined
has been modified so that it no longer defines the tested command to be\relax
if it was previously undefined.