10

So, I was looking for a way to set some commands to one of a few alternative definitions (i.e. setting \mycommand to one version of the command or others with a simple command invocation), and was hoping to be able to do that with \let and \csname, but trying to compile the following produces no output and complains about missing \begin{document}, extra \endcsname and missing \endcsname inserted.

\documentclass{article}

\newcommand*\letprefix[2]{%
\expandafter\let\csname#1\endcsname\csname#1#2\endcsname %
}

\newcommand*\mycommandversion{I want to use this as ``\\mycommand''}
\letprefix{mycommand}{version}

\begin{document}
Hello!
\mycommand
\end{document}

I've also tried using \def and \newcommand instead of \let and in both cases the document does get built but \mycommand doesn't print anything (the document only contains "Hello!") without any errors or warnings.

I tried it unsuccesfully with lualatex, pdflatex and pdftex with the following:

\def\letprefix #1#2{%
\expandafter\let\csname#1\endcsname\csname#1#2\endcsname %
}

\def\mycommandversion {I want to use this as ``\\mycommand''}
\letprefix{mycommand}{version}

Hello!
\mycommand
\bye

I'm not very familiar with using macros to define other macros, I haven't found anything about using \let in this way (maybe it isn't possible?) and can't understand why the version with \def and \newcommand wouldn't work based on what I found about those instead. Any pointers on how to achieve what I'm trying to do and why this code doesn't work?

1
  • 1
    \newcommand*\letprefix[2]{\expandafter\let\csname#1\expandafter\endcsname\csname#1#2\endcsname} you need to also expand the 2nd \csname, which I do by adding an extra \expandafter. May 11 '20 at 16:29
11

The problem with the OP's syntax is that the first \csname of the \let was expanded into a token, but not the 2nd. One nice trick (learned from David C) is that you can insert \expandafter inside a \csname, just before the \endcsname, to expand the next thing that follows, before closing out the first \csname expansion! That is what I do here, so that both \csnames are expanded into cs-tokens, before the \let is evaluated.

\documentclass{article}

\newcommand*\letprefix[2]{%
  \expandafter\let\csname#1\expandafter\endcsname\csname#1#2\endcsname}

\newcommand*\mycommandversion{I want to use this as ``\textbackslash
  mycommand''}
\letprefix{mycommand}{version}

\begin{document}
Hello!
\mycommand
\end{document}

enter image description here

1
  • Ah, I see, thank you, that works perfectly!
    – verglasz
    May 11 '20 at 16:50
9

With etoolbox you already have a handy tool:

\documentclass{article}
\usepackage{etoolbox}

\newcommand*\letprefix[2]{%
  \csletcs{#1}{#1#2}%
}

\newcommand*\mycommandversion{I want to use this as ``\textbackslash mycommand''}
\letprefix{mycommand}{version}

\begin{document}
Hello!
\mycommand
\end{document}

No need to remember complex sequences of \expandafter.

5

The answer of Steven B. Segletes says it all.

An alternative less efficient approach is exchanging tokens after applying \csname..\endcsname:

\documentclass{article}

\newcommand\exchange[2]{#2#1}%
\newcommand*\letprefix[2]{%
  \expandafter\exchange\expandafter{\csname#1#2\endcsname}{%
    \expandafter\let\csname#1\endcsname= %
  }%
}%

\newcommand*\mycommandversion{%
  I want to use this as ``\textbackslash mycommand''%
}%

\letprefix{mycommand}{version}

\begin{document}
Hello!
\mycommand
\end{document}

This is a link to the .jpg-file of Steven B. Segletes' answer.
(The image comes from a link to the .jpg-file of Steven B. Segletes' answer.)


A more "generic" approach to the matter could be a macro \NameToCs:

The TeXbook explains a nice feature when it comes to defining macros: In the ⟨parameter text⟩ of a macro-definition you can use #{-notation for a macro whose last argument will be delimited by a left curly brace { which—unlike other argument-delimiters—will be re-inserted as if it had been left in place.

Thus I sometimes use a macro-mechanism \NameToCs which processes an argument which is delimited by a left curly brace ({) and another argument which is nested in curly braces.

The argument nested in curly braces is taken for the name of a ⟨control sequence token⟩ which is to be constructed via \csname..\endcsname.

\NameToCs works as follows:

\NameToCs⟨stuff not in curly braces⟩{NameOfCs}
→
⟨stuff not in curly braces⟩\NameOfCs

(If you wish to obtain only the control-sequence-token \NameOfCs, then you can leave ⟨stuff not in curly braces⟩ empty: \NameToCs{NameOfCs} → \NameOfCs)

\makeatletter
\newcommand\exchange[2]{#2#1}%
\@ifdefinable\NameToCs{\long\def\NameToCs#1#{\romannumeral0\innerNameToCs{#1}}}%
\newcommand\innerNameToCs[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\makeatother

There are various uses for such a macro:

  1. \NameToCs{foo}\foo
  2. \NameToCs\string{foo}\string\foo
  3. \NameToCs\meaning{foo}\meaning\foo
  4. \NameToCs\global\long\def{foo}...\global\long\def\foo...
  5. \NameToCs\newcommand*{foo}...\newcommand*\foo...
  6. \NameToCs\NameToCs\global\let{foo}={bar}\NameToCs\global\let\foo={bar}\global\let\foo=\bar

Usage-example 6 can be applied in your scenario:

\documentclass{article}

\makeatletter
\newcommand\exchange[2]{#2#1}%
\@ifdefinable\NameToCs{\long\def\NameToCs#1#{\romannumeral0\innerNameToCs{#1}}}%
\newcommand\innerNameToCs[2]{\expandafter\exchange\expandafter{\csname#2\endcsname}{ #1}}%
\makeatother

\newcommand*\mycommandversion{%
  I want to use this as ``\textbackslash mycommand''%
}%

\newcommand*\letprefix[2]{%
  \NameToCs\NameToCs\let{#1}= {#1#2}%
}%

\letprefix{mycommand}{version}

\begin{document}
Hello!
\mycommand
\end{document}

This is a link to the .jpg-file of Steven B. Segletes' answer.
(The image comes from a link to the .jpg-file of Steven B. Segletes' answer.)


Be aware that a simple \let-assignment does not always work out for control-sequences which initiate the carrying-out of a "macro-based mechanism" that internally consists of several macros.

  • This is the case, e.g., with LaTeX commands that process optional arguments defined in terms of \newcommand or with LaTeX commands that are defined as robust macros by \DeclareRobustCommand.
    With such commands the command \LetLtxMacro of the package letltxmacro takes care of the internal macros also.
  • This is also the case with commands defined in terms of xparse's \NewDocumentCommand.
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.