# Is there a better way to “absorb” the subscript than this \@ifnextchar-hackery?

In this example document, I want to make a math relation called R which gets typeset as R^X, but as a math relation. But I want to maybe be able to subscript it. The macro \myRbad looks okay without the subscript, but with a subscript it looks wrong because the subscript occurs "after" the superscript instead of being underneath it as it should be. The macro \myRgood looks correct in either case. It works by checking whether the next character is _ and if it is, gobbling the _ and delegating to another macro which typesets the subscripted version. I wondered though, whether there's a more straightforward way than this to make LaTeX do what I want.

\documentclass[a4paper]{amsart}

\def\myRbad{\mathrel{R^X}}

\makeatletter
\def\@myRgood@#1{\mathrel{R^X_{#1}}}
\def\myRgood{\@ifnextchar_{\expandafter\@myRgood@\@gobble}{\mathrel{R^X}}}
\makeatother

\begin{document}

$a \myRbad b$

$a \myRbad_Y b$

$a \myRgood b$

$a \myRgood_Y b$

$a R^X_Y b$

$a \mathrel{R^X}_Y b$

$a \mathrel{R^X_Y} b$

\end{document}


# Edit:

As a bonus, here is a macro that automates the creation of macros like \myRgood (using the improved method shown by @egreg's answer). (You have to \usepackage{xstring}.)

\makeatletter
\def\makeprocessedmathabsorbsubscript#1#2#3{
\edef\@themacroname{\string#1}%
\saveexpandmode%
\fullexpandarg%
\StrGobbleLeft{\@themacroname}{1}[\@themacroname]%
\restoreexpandmode%
\ifcsname\@themacroname\endcsname%
\errmessage{The macro "\@themacroname" already exists}%
\fi%
\ifcsname @\@themacroname @\endcsname%
\errmessage{Something strange is happening.
I want to create an internal macro for "\@themacroname",
but it exists already}%
\fi%
\expandafter\def\csname @\@themacroname @\endcsname##1##2{#2{#3_{##2}}}%
\edef#1{%
\unexpanded{\@ifnextchar_}%
{\unexpanded\expandafter{\csname @\@themacroname @\endcsname}}%
\unexpanded{{#2{#3}}}%
}
}
\makeatother


Now one can write something like:

\makeprocessedmathabsorbsubscript{\myRbetter}{\mathrel}{R^X}


and the macro \myRbetter is provided.

-

## 1 Answer

Just define \@myRgood with two arguments and use the second one. When you call \@myRgood you know that _ follows.

\documentclass[a4paper]{amsart}

\makeatletter
\def\@myRgood@#1#2{\mathrel{R^X_{#2}}}
\def\myRgood{\@ifnextchar_{\@myRgood@}{\mathrel{R^X}}}
\makeatother

\begin{document}

$a \myRgood b$

$a \myRgood_Y b$

\end{document}


The “abstract” version; a trick similar to the one used for commands with optional arguments is used; the inner macro related to \myRgood is \\myRgood (with a backslash in its name).

\documentclass[a4paper]{amsart}

\makeatletter
\newcommand{\newrelation}[2]{% #1 = control sequence, #2 = replacement text
\@ifdefinable{#1}{%
\def#1{%
\@ifnextchar_{\csname\string#1\endcsname}{\mathrel{#2}}%
}%
\@namedef{\string#1}##1##2{\mathrel{#2_{##2}}}%
}%
}
\makeatother

\newrelation{\myRgood}{R^X}

\begin{document}

$a \myRgood b$

$a \myRgood_Y b$

\end{document}


A LaTeX3 version of the same

\documentclass[a4paper]{amsart}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\myRgood}{ }
{
\peek_catcode_remove:NTF \c_math_subscript_token
{ \hammerite_myR:n }
{ \hammerite_myR:n {} }
}
\cs_new_protected:Npn \hammerite_myR:n #1
{
\mathrel
{
R^X
\tl_if_empty:nF { #1 } { \c_math_subscript_token { #1 } }
}
}
\ExplSyntaxOff

\begin{document}

$a \myRgood b$

$a \myRgood_Y b$

\end{document}


Here's the “abstract” version

\documentclass[a4paper]{amsart}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\newrelation}{mm}
{% #1 = control sequence, #2 = replacement text
\NewDocumentCommand{#1}{}
{
\peek_catcode_remove:NTF \c_math_subscript_token
{
\hammerite_relation:nn { #2 }
}
{
\hammerite_relation:nn { #2 } { }
}
}
}

\cs_new_protected:Npn \hammerite_relation:nn #1 #2
{
\mathrel
{
#1
\tl_if_empty:nF { #2 } { \c_math_subscript_token { #2 } }
}
}
\ExplSyntaxOff

\newrelation{\myRgood}{R^X}

\begin{document}

$a \myRgood b$

$a \myRgood_Y b$

\end{document}

-
Oh, good idea. I will leave this open a while in case anyone suggests an alternative method that is different entirely (e.g. doesn't use \@ifnextchar), but I expect I will end up accepting this answer. – Hammerite Jan 17 '14 at 12:40
@Hammerite I don't think there's a way to avoid \@ifnextchar or equivalent method. – egreg Jan 17 '14 at 13:51