# How to concatenate command names

I would like to be able to perform an "indexed" assign by concatenating two (or more) portions of a command name, both for creating a new command and for referencing an existing command. Here is an example that shows that I need. Non-working, of course.

\documentclass[10pt]{article}

\usepackage{mathtools}
\usepackage{fontspec}
\usepackage{unicode-math}
\usepackage{lualatex-math}

\setmainfont{STIX Two Text}
\setmathfont{STIX Two Math}

\newCommand oldabc  123               % Existing value.

\newcommand indexedSet[1] {           % Macro to do an indexed assign and an indexed reference.
\newcommand  val##1 {old##1}
}

\indexedSet{abc}                      % Defines valabc as 123

\begin{document}

\end{document}

• Maybe this helps: tex.stackexchange.com/q/39380/121799 – user121799 Jun 4 at 23:56
• Thank you. That worked. – Michael Lee Finney Jun 5 at 0:38

It is partly a matter of opinion, but the easiest way to do this is to use the \csdef and \csuse commands from the etoolbox package. At least using these commands is easier for me to read as you can define \IndexedSet as

\newcommand\indexedSet[1]{\csdef{val#1}{\csuse{old#1}}}


Depending on what you put into these commands and how often you change them you might to actually use

\newcommand\indexedSet[1]{\csxdef{val#1}{\csuse{old#1}}}


as this will force the "old" command to expand to its current value. Finally, you should also check to make sure that the old command is actually defined, which you can do using \ifcsdef:

\newcommand\indexedSet[1]{\csxdef{val#1}{\ifcsdef{old#1}{\csuse{old#1}}{???}}}


So, if the "old" command is not defined then the new command is set to ???.

Here is a full MWE:

\documentclass[10pt]{article}

\usepackage{etoolbox}
\newcommand\oldabc{123} % initial value.

% Macro to do an indexed assign and an indexed reference.
\newcommand\indexedSet[1]{\csxdef{val#1}{\ifcsdef{old#1}{\csuse{old#1}}{???}}}

\begin{document}
abc: \indexedSet{abc} \valabc

pqf: \indexedSet{pqf} \valpqf
\end{document}


that produces the expected output:

• Thank you. That looks like a good solution as well. It doesn't seem like it saves much over wrapping \csname and \encsaname around the parts of the name. I have already incorporated the suggestion by marmot which has saved me over a 1000 lines in my package. Adding looping (not that I know how to do that in TeX yet) would probably save me another 100 or 150 lines once I am done. That is a comparatively minor optimization and I will look at that once this change is complete. Probably later tonight. – Michael Lee Finney Jun 5 at 2:13
• @MichaelLeeFinney Yes that's exactly right: this just save your from writing \csname...\]endcsname everywhere - and, I think, it is easier to read. There are various different ways of looping and without see your code it is difficult to say what will work best for you. For looping over comma separated lists look at \docsvlist in the etoolbox package. For "standard" for-loops have a look at \foreach in pgffor -- or delve into the wonders of LaTeX3 package – Andrew Jun 5 at 6:09

Thanks to a suggest by marmot, the following works.

\documentclass[10pt]{article}

\usepackage{mathtools}
\usepackage{fontspec}
\usepackage{unicode-math}
\usepackage{lualatex-math}

\setmainfont{STIX Two Text}
\setmathfont{STIX Two Math}

\newcommand \oldabc  {123}            % Existing value.

\newcommand\indexedSet[1]  {
\expandafter\def\csname val#1\endcsname{\csname old#1\endcsname} }

\indexedSet{abc}                      % Defines valabc as 123

\begin{document}

\valabc

\end{document}

• Expanding \valabc does not yield 123 but does yield \csname oldabc\endcsname. Perhaps \newcommand\indexedSet[1]{\expandafter\def\csname val#1\expandafter\expandafter\expandafter\endcsname\expandafter\expandafter\expandafter{\csname old#1\endcsname}} – Ulrich Diez Jun 5 at 13:59

Just use \csname with appropriate expansions.

\documentclass{article}

\newcommand{\indexedSet}[1]{%
\expandafter\let\csname val#1\expandafter\endcsname\csname old#1\endcsname
}

\newcommand\oldabc{123}

\begin{document}

\indexedSet{abc}

\valabc

\end{document}


With etoolbox you can shorten the definition:

\usepackage{etoolbox}

\newcommand{\indexedSet}[1]{\csletcs{val#1}{old#1}}

\documentclass[10pt]{article}

%----------------------------------------------------------------------
% \name <tokens not nested in braces>{macroname}
%  ->  <tokens not nested in braces>\macroname
% Examples:
%   \name{foo} -> \foo
%   \name\string{foo} -> \string\foo
%   \name\meaning{foo} -> \meaning\foo
%   \name\name\let{foo}={bar} -> \name\let\foo={bar} -> \let\foo=\bar
%......................................................................
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{%
\expandafter\exchange\expandafter{\csname #2\endcsname}{ #1}%
}%
\newcommand\exchange[2]{#2#1}%

\usepackage{mathtools}
%\usepackage{fontspec}
%\usepackage{unicode-math}
%\usepackage{lualatex-math}

%\setmainfont{STIX Two Text}
%\setmathfont{STIX Two Math}

\newcommand\oldabc{123}               % Existing value.

\newcommand\indexedSet[1]{%           % Macro to do an indexed assign and an indexed reference.
\name\name{@ifdefinable}{val#1}{%
\name\name\let{val#1}={old#1}%
}%
}%

\indexedSet{abc}                      % Defines valabc as 123

\begin{document}

\texttt{\string\oldabc: \meaning\oldabc}

\texttt{\string\valabc: \meaning\valabc}

\texttt{\name\string{valabc}: \name\meaning{valabc}}

\end{document}


Adding some raising of error-messages in case \valabc is already defined or \oldabc is undefined, could look like this:

\documentclass[10pt]{article}

%----------------------------------------------------------------------
% \name <tokens not nested in braces>{macroname}
%  ->  <tokens not nested in braces>\macroname
% Examples:
%   \name{foo} -> \foo
%   \name\string{foo} -> \string\foo
%   \name\meaning{foo} -> \meaning\foo
%   \name\name\let{foo}={bar} -> \name\let\foo={bar} -> \let\foo=\bar
%......................................................................
\newcommand\name{}%
\long\def\name#1#{\romannumeral0\innername{#1}}%
\newcommand\innername[2]{%
\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}%
}%
\newcommand\exchange[2]{#2#1}%
%----------------------------------------------------------------------
% \PreambleMacroError{\macro}{<error text>}{<immediate-help-text>}
%......................................................................
\begingroup\makeatletter\@firstofone{%
\endgroup
\newcommand*\PreambleMacroError[3]{%
\GenericError{%
\space\space\space\@spaces\@spaces\@spaces
}{%
LaTeX Error: Inapproriate usage of macro \string#1\on@line.\MessageBreak
(\string#1 is defined in the document's preamble.)\MessageBreak
Problem: #2%
}{%
Have a look at the comments in the preamble of this document.%
}{#3}%
}%
}%
%----------------------------------------------------------------------

\usepackage{mathtools}
%\usepackage{fontspec}
%\usepackage{unicode-math}
%\usepackage{lualatex-math}

%\setmainfont{STIX Two Text}
%\setmathfont{STIX Two Math}

\newcommand\oldabc{123}               % Existing value.

\newcommand\indexedSet[1]{%           % Macro to do an indexed assign and an indexed reference.
\name{@ifundefined}{old#1}{%
\PreambleMacroError{\indexedSet}%
{Macro \name\string{old#1} undefined}%
{Setting \name\string{val#1} to \name\string{old#1}
does only make sense when\MessageBreak
\name\string{old#1} is defined.}%
\name{@ifundefined}{val#1}{}{%
\PreambleMacroError{\indexedSet}%
{Setting \name\string{val#1} to \name\string{old#1} should not
override an existing definition of\MessageBreak
\name\string{val#1}.}%
}%
}{%
\name{@ifundefined}{val#1}{%
\name\name\let{val#1}={old#1}%
}{%
\PreambleMacroError{\indexedSet}%
{Setting \name\string{val#1} to \name\string{old#1} should not
override an existing definition of\MessageBreak
\name\string{val#1}.}%
}%
}%
}%

\indexedSet{abc}                      % Defines valabc as 123

\begin{document}

\texttt{\string\oldabc: \meaning\oldabc}

\texttt{\string\valabc: \meaning\valabc}

\texttt{\name\string{valabc}: \name\meaning{valabc}}

\end{document}