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?

2
  • 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, 2019 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, 2019 at 10:23

1 Answer 1

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 {...}).

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .