# How to avoid defining something inside of a macro that uses '\csname \endcsname'?

by Bob Vesterman   Last Updated July 12, 2019 09:23 AM - source

The following code gives no error and works fine:

\documentclass{memoir}

\def\ThingyFred {This is the thingy named Fred}

\begin{document}
\chapter{Fred}
\ThingyFred
\end{document}


And the following code gives an error

"Undefined control sequence. \ThingyJoe",

which is what I would expect and hope it would do:

\documentclass{memoir}

\def\ThingyFred {This is the thingy named Fred}

\begin{document}
\chapter{Fred}
\ThingyJoe
\end{document}


But for various reasons, I want (in the main body of the document) to refer to things like \Thingy{Fred}, not \ThingyFred. The following works fine:

\documentclass{memoir}

\def\RawThingyFred {This is the thingy named Fred}

\def\Thingy#1 {\csname RawThingy#1\endcsname}

\begin{document}
\chapter{Fred}
\Thingy{Fred}
\end{document}


But, contrary to my naive expectations and hopes, the following code does not give an error (it instead treats \Thingy{Joe} as an empty variable):

\documentclass{memoir}

\def\RawThingyFred {This is the thingy named Fred}

\def\Thingy#1 {\csname RawThingy#1\endcsname}

\begin{document}
\chapter{Fred}
\Thingy{Joe}
\end{document}


After investigating a little more, it seems to me the problem is, when you do a \Thingy{Joe}, the \def\Thingy#1 \csname RawThingy#1\endcsname does not merely translate to \RawThingyJoe, but additionally defines \RawThingyJoe. For example, the following returns the error, I expect:

\documentclass{memoir}

\def\RawThingyFred {This is the thingy named Fred}

\def\Thingy#1 {\csname RawThingy#1\endcsname}

\begin{document}
\chapter{Fred}
\RawThingyJoe
\Thingy{Joe}
\end{document}


But the following does not get an error:

\documentclass{memoir}

\def\RawThingyFred {This is the thingy named Fred}

\def\Thingy#1 {\csname RawThingy#1\endcsname}

\begin{document}
\chapter{Fred}
\Thingy{Joe}
\RawThingyJoe
\end{document}


Apparently, in the first case, it sees \RawThingyJoe and has no idea what that means, whereas in the second case it sees \Thingy{Joe}, decides that \RawThingyJoe therefore means an empty string, and then sees \RawThingyJoe, which it interprets as an empty string.

Is there a way to take the "define a macro that takes a parameter" route, but still get the error-checking I had expected?

Tags :

As egreg wrote, \csname ... \endcsname defines the control sequence token to be \let-equivalent to \relax if it isn't already defined (you can think of it as a side effect of \csname). With e-TeX extensions, you can use \ifcsname to test whether a control sequence is defined, without defining it (no side effect):

\documentclass{article}

\newcommand*{\RawThingyFred}{This is the thingy named Fred}

\newcommand*{\Thingy}[1]{%
\ifcsname RawThingy#1\endcsname
\csname RawThingy#1\endcsname
\else
\errmessage{\string\RawThingy#1 is undefined}%
\fi
}

\begin{document}

\Thingy{Fred}% okay
\Thingy{Joe}% prints \RawThingyJoe is undefined.

\end{document}


You can see other techniques for this kind of test here.


frougon
July 12, 2019 08:55 AM