Non-alphabet letter in \csname …\endcsname

Why can't I get what I want in the following code? MWE:

\documentclass{article}
\begin{document}
%
\def\aaa*{*}
\def\aaaAAA{AAA}
|\csname aaaAAA\endcsname|% typeset |AAA| as I desired.
|\csname aaa*\endcsname|% I want to get |*|, but get ||. So, what's wrong with my code?
%
\end{document}

• \def\aaa*{*} does not define a macro called \aaa*. It defines a macro called \aaa that must always be followed by a *. |\csname aaa\endcsname*| would give you the output of \aaa*. To define \aaa* you need \expandafter\def\csname aaa*\endcsname{*}. – moewe Feb 1 '19 at 8:17

That's because \csname aaa*\endcsname does not exist and therefore defaults to \relax which typesets nothing. Why does it not exist? Well, the problem is similar to No \makeatletter required?:

In \def\aaa*{*}, * does not form part of the definition, but instead forms part of the parameter text used. In order to define a macro to include a * in the definition name you'll have to use

\expandafter\def\csname aaa*\endcsname{*}% Similar to \@namedef{aaa*}{*}


Consider the following example

\def\aaa*{*}

\show\aaa*


Running TeX on it (any flavor), will report as follows on the console

> \aaa=macro:
*->*.
l.3 \show\aaa
*
?


How do we read it? The primitive command \show reports the meaning of the following token; the to lines before the question mark tell us that \aaa* are two tokens, because * appears in the continuation line.

TeX is also telling us that \aaa is a macro that has a nonempty parameter text (what's reported before ->) consisting of an asterisk. In other words, \def\aaa*{*} instructs TeX that \aaa must be followed by * and the two tokens will be replaced by *.

For instance, you can call it also as

\aaa *


because the space after \aaa is ignored when building tokens from input.

If you want to use \csname, then it should be

\csname aaa\endcsname *


(the space before * is optional).

In case you're wondering how *-variants are implemented in LaTeX, here it is:

\newcommand{\foo}{\@ifstar\foostar\foonostar}
\newcommand{\foostar}{<what we want \foo* to do>}
\newcommand{\foonostar}{<what we want \foo to do>}


Possible arguments have to be grabbed by \foostar or \foonostar, depending on the desired syntax.

The approach with xparse is slightly different, but the command will not have the * as part of the name nonetheless.

• Thank you so much for these detail explanations – lyl Feb 1 '19 at 12:44