48

I thought the way to undo a \def was to define it to \relax, but that does not appear to work. Also, am not sure why this produces no output if I try to use \def instead of \let in my attempt to do an undef.

\documentclass{article}

\begin{document}

\def\CaseA{}%

\ifdefined\CaseA%
    \def\ProcessCaseA{}%
    % Do stuff that uses \ProcessCaseA
    %\def\ProcessCaseA\relax% no output if use this, and comment next line
    \let\ProcessCaseA\relax% no output if comment this, and use above line
\fi

% Now do stuff that requires \ProcessCaseA NOT be defined
\ifdefined\ProcessCaseA
    ERROR: \textbackslash ProcessCaseA is still defined
\else
    SUCCESS: \textbackslash ProcessCaseA is not defined
\fi

\end{document}
Peter Grill
  • 223,288

3 Answers3

34

You need to let it to undefined, not relax, try this

\providecommand*\@nameundef[1]{%
  \expandafter\let\csname #1\endcsname\@undefined}

See comments by Ulrich below for some caveats.

yannisl
  • 117,160
  • 12
    ... conditional on the fact that no control sequence named \@undefined is defined. (But I think that's assumed at some places in the kernel as well, so \def@undefined{} would likely break a lot of stuff anyway, so the user will notice.) – Ulrich Schwarz Jun 14 '11 at 07:09
  • 12
    @UlrichSchwarz The command \@undefined is used more than 800 times in my texmf tree, so it is a good assumption. – yo' Mar 06 '12 at 10:23
27

The macro \ifdefined is not part of basic TeX, so I suppose you are getting it from eTeX. In that case, you should consider using the etoolbox package, which provides a few wrapper functions \ifdef{\macro}{true}{false} and \ifundef{\macro}{true}{false}. The etoolbox manual tells me that the latter has the convenient effect of registering a macro \let to \relax as being "undefined", which sounds like what you want.

Alternatively, depending on the situation, if you truly wish to erase a macro from TeX's memory, you can define it in a group and then leave the group. Note that this is quite different from \letting it to \relax, since if TeX tries to read \macro before it has ever been \def'd or \let, it will raise an error, while if you have written \let\macro=\relax, it will just do nothing.

Ryan Reich
  • 37,958
  • Adding \begingroup and \endgroup worked great. Thanks. – Peter Grill Jun 14 '11 at 00:22
  • 11
    etoolbox also has \undef. – Philipp Jun 14 '11 at 05:27
  • @Philipp: so it does! I never went to that section of the manual. – Ryan Reich Jun 14 '11 at 13:53
  • 4
    @RyanReich Could you update your answer including an example of the use of \begingroup and \endgroup? I understand the spirit, but I'm having problems implementing it! Thank you. – Dox Apr 24 '15 at 12:08
  • 1
    Note, the "define in group then leave group" solution as far as I can see only works when the original definition can be moved inside a group. If it's already defined globally/in the current level, no amount of group manipulating can undefine it. // – user202729 Oct 25 '22 at 16:39
26

The assignment \let\xyz\relax makes \xyz "undefined" as far as the \@ifundefined test is concerned. So

\makeatletter
\let\xyz\relax
\@ifundefined{xyz}{LaTeX undefined}{LaTeX defined}\par
\ifdefined\xyz e-TeX defined\else e-TeX undefined\fi\par
\ifcsname xyz\endcsname e-TeX defined\else e-TeX undefined\fi\par

would print

LaTeX undefined
e-TeX defined
e-TeX defined

The only safe way to "undefine" a command is to define it inside a group: at the end of it the definition will vanish. There is \undef in etoolbox that relies on the fact that a specific control sequence (\etb@undefined) will never be defined by anybody.

Choosing between the \@ifundefined and \ifdefined tests is a matter of convenience and mostly depends on what you need. Notice that the argument to \@ifundefined is the macro's name, without the backslash.

egreg
  • 1,121,712