# How should I /protect this command for use in \csname?

In the process of learning how to use \csname, I'm trying to create a macro that allows one to specify integers as arguments and then will yield some content specific to the arguments, like this:

\DoContent{1}{3}


My current full-example attempt:

\documentclass[10pt]{article}

\usepackage{xifthen}

%End-Content output
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement
\newcommand{\GetNumberText}[1]
{
\ifthenelse{\equal{#1}{1}}{One}{}
\ifthenelse{\equal{#1}{2}}{Two}{}
\ifthenelse{\equal{#1}{3}}{Three}{}
\ifthenelse{\equal{#1}{4}}{Four}{}
\ifthenelse{\equal{#1}{5}}{Five}{}
}

%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}

%this does not compile: desired functionality
%\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

%this compiles: literal example
\newcommand{\DoContent}[2]{\AssembleNumCmd{One}{Three}}

\begin{document}

\DoContent{1}{3}

\end{document}


This should produce

One Three content

It appears that I can't use any conditional statements inside of the definition of\GetNumberText and still pass \GetNumberText{1} to \AssembleNumCmd. The document doesn't compile if I use the version of \DoContent that I have commented there (which is what I want to do).

Obviously, this is some somewhat silly gymnastics, and I'm open to better overall approaches. But, I still need want to know why this relatively simple method isn't working, and what to do to fix it.

I've tried using \protect here and there, and using a different "switch" macro that uses \ifx instead of \ifthenelse, among other smaller changes, and nothing seems to compile without error (" Missing \endcsname inserted", and so forth).

Is this a problem with my use of \csname? Or am I just being naive about macro expansion and fragility?

• You are trying to use \ifthenelse inside a \csname. This won't work, \ifthenelse is not expandable. Oct 21, 2015 at 18:11
• As a side remark, be careful with all the extra spaces in your \GetNumberText. There should be a bunch of %'s. Beware that in LaTeX3 code à la @egreg, \ExplSyntaxOn makes spaces in the source completely disappear (they must be input explicitely as ~). Even with an expandable switch which would work in a \csname.. you have to be careful with spaces, as the so-built name may well end up containing such probably unintended spaces.
– user4686
Oct 21, 2015 at 20:05

Here is a expl3 version, storing One, .... , Ten in a \clist variable:

\documentclass[10pt]{article}

\usepackage{xparse}

\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement

\ExplSyntaxOn
\clist_new:N \g_turanc_numbername_clist
\clist_set:Nn \g_turanc_numbername_clist {One, Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten}

\NewDocumentCommand{\GetNumberText}{m}{%
\clist_item:Nn \g_turanc_numbername_clist {#1}
}
\ExplSyntaxOff

%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}

\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{1}{5}

\end{document}


Old Version

I replaced the \ifthenelse conditional by a 'simpler' \ifcase ...\or ...\fi statement for the individual cases. I think it might work with other packages as well.

\documentclass[10pt]{article}

\usepackage{xifthen}

%End-Content output
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement

\newcommand{\GetNumberText}[1]
{%
\ifcase #1
\or
One%
\or
Two%
\or
Three%
\or
Four%
\or
Five%
\fi
}

%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{\csname #1#2\endcsname}

%This does not compile: desired functionality
\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

%this compiles: literal example
%\newcommand{\DoContent}[2]{\AssembleNumCmd{One}{Three}}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{1}{5}

\end{document}


**\ifx version:

There mustn't be white space characters so be careful when testing etc:

\documentclass[10pt]{article}

%End-Content output
\newcommand{\OneOne}{One One content}
\newcommand{\OneTwo}{One Two content}
\newcommand{\OneThree}{One Three content}
\newcommand{\OneFour}{One Four content}
\newcommand{\OneFive}{One Five content}
\newcommand{\TwoOne}{Two One content}
\newcommand{\TwoTwo}{Two Two content}
% and so on....

%Translator "Switch" statement

\newcommand{\GetNumberText}[1]
{%
\ifx#11%
One%
\else
\ifx#12%
Two%
\else
\ifx#13%
Three%
\else
\ifx#14%
Four%
\else
\ifx#15%
Five%
\fi
\fi
\fi
\fi
\fi
}

%csname macro to assemble the content-containing macro
\newcommand{\AssembleNumCmd}[2]{%
\csname #1#2\endcsname%
}

\newcommand{\DoContent}[2]{\AssembleNumCmd{\GetNumberText{#1}}{\GetNumberText{#2}}}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{1}{2}

\DoContent{1}{5}

\end{document}

• I would never use ifcase or long if-else-test for this sort of things. Difficult to extend and debug and maintain. Oct 21, 2015 at 18:21
• @UlrikeFischer: Yes, it's not nice, but it works ;-)
– user31729
Oct 21, 2015 at 18:27
• Thanks for this. I wasn't even aware of \ifcase. But why does this work and not a set of \ifx statements? I tried the latter and it had the same problem as using \ifthenelse. Wouldn't \ifx be just as primitive as \ifcase? Oct 21, 2015 at 18:48
• @turanc: It should work using \ifx but I don't know how you did your code actually
– user31729
Oct 21, 2015 at 18:52
• @turanc: See also my update with the expl3 version
– user31729
Oct 21, 2015 at 18:56

As I already wrote in the comment, using \ifthenelse in \csname won't work.

Beside this you are overcomplicating things a lot. You already know that command names can contains other things then letters, so then why don't do use this knowledge for the content definitions?

\documentclass[10pt]{article}

\makeatletter
\@namedef{text1-1}{One One content}
\@namedef{test1-2}{One Two content}
\makeatother

\newcommand{\DoContent}[2]{\csname test#1-#2\endcsname}

\begin{document}

\DoContent{1}{2}

\end{document}


• Why not \@nameuse{test#1-#2} then instead of \csname ... \endcsname?
– user31729
Oct 21, 2015 at 18:33
• @ChristianHupfer: tradition ... Oct 21, 2015 at 18:39
• Aha ... well, I improved my solution to be more maintainable and easier to debug ;-)
– user31729
Oct 21, 2015 at 18:44
• Thanks for this response. I didn't know about \@namedef. I marked the next response as answered, though, since it was closer to answering the original question. Gave this an upvote, however. Oct 21, 2015 at 23:07
• \@namedef is only a wrapper for \expandafter\def\csname ...\endcsname{ ...} . And I didn't follow your route with the string comparision as I think it is inefficient: it is quite unnecessary to compare the actual string with all lot of other strings all the time only to get its content text. Oct 22, 2015 at 7:13

As Ulrike pointed out, \ifthenelse cannot be used in \csname...\endcsname, where only macros fully expandable to characters are allowed.

Here's a different implementation using a case switch:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\DoContent}{mm}
{
\str_case:nnF { #1-#2 }
{
{1-1}{One~One~content}
{1-2}{One~Two~content}
{1-3}{One~Three~content}
{1-4}{One~Four~content}
{1-5}{One~Five~content}
{2-1}{Two~One~content}
{2-2}{Two~Two~content}
}
{Invalid~choice}
}
\ExplSyntaxOff

\begin{document}

\DoContent{1}{3}

\end{document}


A possibly better interface for adding cases:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\DoContent}{mm}
{
\str_case:nVF { #1-#2 } \g_turanc_choices_tl
{Invalid ~ choice}
}

{
\clist_map_inline:nn { #1 }
{
\tl_gput_left:Nn \g_turanc_choices_tl { ##1 }
}
}

\tl_new:N \g_turanc_choices_tl

\ExplSyntaxOff

{1-1}{One One content},
{1-2}{One Two content},
{1-3}{One Three content},
{1-4}{One Four content},
{1-5}{One Five content},
}

{2-1}{Two One content},
}
{2-2}{Two Two content},
}

\begin{document}

\DoContent{1}{3}

\DoContent{2}{2}

\DoContent{9}{9}

\end{document}


Note that \AddContent is cumulative, so pairs can be added even after \begin{document}, wherever they become necessary. If you add a pair twice, the one in the last \AddContent wins, so you can later override a choice made at startup.