What is the difference between \ifx\somecommand\undefined and \ifdefined\somecommand\else?
Of course, they have different syntax.
\ifx\cyrdash\undefined
is traditional way to test if a macro is undefined. Of course,\undefined
sould not be defined.There are
\ifdefined
and\ifcsname
primitives in eTeX. They have no other side effects.LaTeX's
\@ifundefined
test if a macro is defined or it has the same meaning of\relax
. Furthermore,\@ifundefined{undefinedfoo}{...}{...}
will makes\undefinedfoo
to be\relax
.
Normally, there is no difference between
\ifx\foo\undefined A \else B \fi
and
\ifdefined\foo B \else A \fi
eTeX primitives may be a little safer. Say, we don't need to worry about whether \undefined
is really undefined.
However, these two usage are different:
% wrong
% \expandafter\ifx\csname foo\endcsname\undefined A \else B \fi % This is always false
\expandafter\ifx\csname foo\endcsname\relax A \else B \fi % This is \@ifundefined
and
\ifcsname foo\endcsname B \else A \fi
In fact, \csname undefined\endcsname
makes \undefined
to be \relax
, while \ifcsname undefined\endcsname
makes \undefined
unchanged. That's why \ifcsname
in eTeX is necessary.
Test code:
\documentclass{minimal}
\long\def\themeaning#1{\string#1: \meaning#1\par}
\begin{document}
\makeatletter\ttfamily
\def\known{abc}
\let\empty\relax
% initial
\themeaning\known
\themeaning\empty
\themeaning\unknown
\hrulefill
% useful eTeX extension
\ifdefined\known yes\else no\fi\par
\ifdefined\empty yes\else no\fi\par
\ifdefined\unknown yes\else no\fi\par
\hrulefill
% Or
\ifcsname known\endcsname yes\else no\fi\par
\ifcsname empty\endcsname yes\else no\fi\par
\ifcsname unknown\endcsname yes\else no\fi\par
\hrulefill
% the meanings are unchanged
\themeaning\known
\themeaning\empty
\themeaning\unknown
\hrulefill
% LaTeX2e kernel
\@ifundefined{known}{yes}{no}\par
\@ifundefined{empty}{yes}{no}\par
\@ifundefined{unknown}{yes}{no}\par
\hrulefill
% \unknown is changed
\themeaning\known
\themeaning\empty
\themeaning\unknown
\end{document}
According to TeX by Topic \ifx
tests macro equality in the following manner.
Equality of tokens is tested in a stronger sense than the above by
\ifx token1 token2
Character tokens are equal for
\ifx
if they have the same character code and category code.Control sequence tokens are equal if they represent the same TeX primitive, or have been similarly defined by
\font
,\countdef
, or some such. For example,\let\boxhor=\hbox \ifx\boxhor\hbox %is true \font\a=cmr10 \font\b=cmr10 \ifx\a\b %is true
Control sequences are also equal if they are macros with the same parameter text and replacement text, and the same status with respect to
\outer
and\long
. For example,\def\a{z} \def\b{z} \def\c1{z} \def\d{\a} \ifx\a\b %is true \ifx\a\c %is false \ifx\a\d %is false
Tokens following this test are not expanded.
The above refers to ifcat
here, also found in TeX by Topic. I presume you mean \@ifundefined
from the LaTeX kernel when you say \ifundefined
. That is simply implemented in the following manner:
\expandafter \ifx \csname cmd name\endcsname \relax
It uses the fact that the \csname
mechanism expands to \relax
if the csname is not defined. So basically the biggest difference is that \ifx
is more flexible, it allows you to check equality of tokens and not simply whether a csname is defined or not. Furthermore, \ifx
takes a token, whereas \@ifundefined
takes a csname.
Both \undefined
as well as \ifundefined
are macros and there is no guarantee that they have not been redefined by a some package.
The roots of ifundefined
can be found in Exercise 7.7 (p 40) in the TeXBook, where Knuth asked the reader to define such a macro.
When
\csname
is used to define a control sequence for the first time, that control sequence is made equivalent to\relax
until it is redefined. Use this fact to design a macro\ifundefined#1
such that, for example,\ifundefined{TeX} true text\else false text\fi
expands to the true text if
\TeX
hasn't previously been defined, or if\TeX
has been\let
equal to\relax
; it should expand to the false text otherwise.
You can examine their content using meaning:
\documentclass{article}
\begin{document}
\makeatletter
%\def\undefined{\relax}
\texttt{TeX: \meaning\TeX}\\
\texttt{ifundefined: \meaning\ifundefined}\\
\texttt{@ifundefined: \meaning\@ifundefined}\\
\texttt{undefined: \meaning\undefined}\\
\makeatother
\end{document}
As you can see in LaTeX, they are equivalent. LaTeX also offers @ifundefined
.