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}
The code contains this in inside a key value list:
\ifx\dummy#2\dummy\empty\else,#2\fi
The first element in the list is (assuming #2
does not contain ,
):
\ifx\dummy#2\dummy\empty\else
The next is
#2\fi
The \ifx
construct is divided at the comma by the key value parser.
The following implementation expands the options partially to get a valid
key value option list:
\documentclass{article}
\usepackage{lettrine}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\def\eqifcase #1#2#3{\eqifcaseA #1#2#1{#3}\end }
\def\eqifcaseA #1#2#3{\ifx #1#2\eqifcaseDo{#3}\fi \eqifcaseA #1}
\def\eqifcaseDo #1\fi #2\end{\fi #1}
\newcommand*{\Lettrine}[2][]{%
\vspace{-4ex}%
\edef\LettrineNext{%
\noexpand\lettrine[%
lines=1,
findent=%
\eqifcase {#2}{{P}{-0.8em}{T}{-0.6em}}{-0.1em},%
\unexpanded{#1}%
]%
}%
\LettrineNext{\textit{#2}}{}%
}
\begin{document}\thispagestyle{empty}
\section{section 1}
\Lettrine[ante=«]{P}owerfull macro ! »
\section{section 2}
\Lettrine{P}owerfull macro !
\end{document}
New implementation to support additional features
The capital letter can be hidden inside a macro, e.g. \dropCap
.
The letter can consist of more than one token, e.g. D'
.
Macro \DeclareFindents
configures the gap lengths:
\DeclareFindents{-0.1em}{
P=-0.8em,
T=-0.6em,
D'=-1em,
}
The first argument is the default value. Then a key value lists follows; the key
is the letter (also several tokens are possible) and the value the gap length for this letter.
Package kvsetkeys
provides the frame work for a configurable key value parser that compares the list entries with the actual letter. Both the keys and the letters are run through \protected@edef
to expand macros such as \dropCap
.
Example file:
\documentclass{article}
\usepackage{lettrine}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{kvsetkeys}
\makeatletter
\newcommand*{\DeclareFindents}[2]{%
\def\findent@default{#1}%
\def\findent@list{#2}%
}
\DeclareFindents{0pt}{}% initializing
\newcommand*{\findent@set}[1]{%
\protected@edef\findent@letter{#1}%
\let\findent@value\findent@default
\expandafter\kv@parse\expandafter{\findent@list}{%
\protected@edef\kv@key{\kv@key}%
\ifx\findent@letter\kv@key
\let\findent@value\kv@value
\kv@break
\fi
\@gobbletwo % key and value arguments are not needed
}%
}
\newcommand*{\Lettrine}[2][]{%
\vspace{-4ex}%
\findent@set{#2}%
\edef\LettrineNext{%
\noexpand\lettrine[%
lines=1,
findent=\findent@value,
\unexpanded{#1}%
]%
}%
\LettrineNext{\textit{#2}}{}%
}
\makeatother
\DeclareFindents{-0.1em}{
P=-0.8em,
T=-0.6em,
D'=-1em,
}
\begin{document}\thispagestyle{empty}
\section{section 1}
\Lettrine[ante=«]{P}owerfull macro ! »
\section{section 2}
\Lettrine{P}owerfull macro !
\section{section 3}
\Lettrine{D'}Artagnan and his friends.
\section{section 4}
\newcommand*{\dropCap}{D'}
\Lettrine\dropCap Artangan does not drop his friends.
\end{document}
Best Answer
It's one of the uncountable ways to check whether an argument is empty. Almost all of them suffer of some drawback: in the case at hand, the argument mustn't be
\\
.What does
\ifx
do? It compares the two tokens following it, without expanding them. The test return success if both tokens are equal in the sense of\meaning
or\show
:if they are characters (or control sequences
\let
to a character), they must represent the same (character code, category code) pairif they are control sequences (but not
\let
to a character), they must have the same meaning; the cases are too many to list them all.Before analyzing the macro, we should know something about TeX conditional: the abstract form is
where
\ifZ
denotes one of the primitive conditionals. The<test>
can take many forms, depending on\ifZ
(it's empty, in some cases); what is important is that the<true text>
is everything that goes from the end of<test>
to\else
(or\fi
if\else
is missing).So let's see what happens when we call
\mycommand{abc}
, that is, the default argument, which is empty, is substituted to#1
: the tokens that TeX sees areOf course the test is true, because the tokens that follow
\ifx
are both\\
.When we call
\mycommand[xyz]{abc}
, instead, TeX seesand TeX compares
\\
tox
and they are different. But now the<true text>
is(remember: the
<true text>
is what goes from the test to the\else
) and it will be ignored altogether.This test is quite safe, because it doesn't do expansion; however it might fail miserably if the user calls
\mycommand[\\]{abc}
, so often different delimiter tokens are used, which are supposed not to creep into user's input (for instance\uchyph
or\vfuzz
). Another similar test might bewith the caveat that
\if
does expand what's next until two unexpandable tokens remain. The first token is\relax
, which is unexpandable. The second one will be what becomes of the expansion of\noexpand
, that is, the first token of#1
(if non empty) but made unexpandable; if#1
is empty, then\noexpand
applies to\relax
, resulting again in\relax
because it's unexpandable.In both cases some token is reserved (
\\
in the first case,\relax
in the second one). The safest test isbecause the expansion of a non empty
#1
can never give a first token equivalent to\relax
: even if#1
is\relax
,\detokenize{\relax}
will give the string\relax
(the first token of which is the character\
).Again, if
#1
is empty, the test compares\relax
to\relax
; if#1
is not empty, everything will be ignored up to the\else
. Of course it requires that an engine with the e-TeX extensions is run: it won't work with "Knuth TeX".