2

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 the 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 that the problem is that 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 that I would hope:

\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}

So it seems like 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 that I had expected?

  • 1
    From \csname...\endcsname TeX builds a control sequence name; if this name corresponds to an undefined control sequence, TeX defines it as equivalent to \relax. Please, look for \csname in the site: this topic has been discussed several times. – egreg Jul 12 at 8:51
  • 2
    You should be aware of the fact that \def\x#1 {...} and \def\x#1{...} are very different. – egreg Jul 12 at 10:23
6

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.

P.S.: I changed your \defs to \newcommand*, first because \newcommand and \newcommand* ensure you don't accidentally overwrite an existing macro, second because your parameter text had a probably unwanted space (for instance, after #1 in \def\Thingy#1 {...}).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.