1

Based on this code snippet, I concluded that \newcommand commands work by string substitution before expansion:

\newcommand{\double}[1]{#1#1}
\newcounter{dummy}

\thedummy \double{\stepcounter{dummy}} \thedummy

which outputs 0 2, indicating that \stepcounter is appearing twice after \double is expanding. So it's substituted before being expanded/executed.

However, the following code:

\newcommand{\append}[1]{#1long}

\newcommand{\mypi}{3.1}
\newcommand{\mypilong}{3.14159}
\append{\mypi}{4159}

ouptuts 3.1long instead of 3.14159 (which you'd expect from string substitution), indicating that \mypi was expanded prior to being substituted.

What do I have wrong?

2
  • 1
    #1long does not get replaced by \mypilong, but by the five tokens \mypi•l•o•n•g (the bullets are used to show the distinct tokens).
    – egreg
    Jun 19, 2020 at 14:21
  • @daleif Sorry, it was a typo. Fixed now.
    – user218660
    Jun 19, 2020 at 15:06

1 Answer 1

1

TeX doesn't have the concept of “string”. It only works with tokens.

The replacement text of \append consists of a “parameter token”, that will get substituted at call time with the actual argument, followed by four tokens l, o, n and g.

TeX works with tokens and will never “append” them to control sequence names: it will never fuse together two tokens. So when you call \append{\mypi} you get

\mypi•l•o•n•g

(where the bullets are used to mark the boundaries between tokens). Next \mypi is replaced by its definition and you get

3.1long

The {4159} part will be read in next and the final output will be

3.1long4159


Your \double is also a bit problematic. I guess that the proper code you used is

\newcommand{\double}[1]{#1#1}

because \newcommand{\double}[1]{#1}{#1} would produce an error for a misplaced #.


Is it possible to define \append so that \append{\mypi} expands \mypilong? Yes, in various ways. One is

\newcommand{\gobblebackslash}[1]{}
\newcommand{\append}[1]{\csname\expandafter\gobblebackslash\string#1long\endcsname}

Explanation:

  • we want to build a control sequence name from various parts, so \csname...\endcsname is needed;
  • we can use \string\mypi to get the macro name, but there would be the backslash;
  • so we strip the backslash off by expanding \string\mypi first and then letting \gobblebackslash do its job of gobbling one token.

Does this contradict the statement that tokens are never fused together? No. The primitive \csname expands to a single symbolic token build with the tokens it finds until the matching \endcsname.

Note. The code above implicitly assumes that the value of \escapechar is the usual one.

3
  • Thanks, this makes much more sense now. If I understand correctly, all the tokens between \csname and \endcsname are converted into strings and concatenated, then the block of tokens as a whole is considered to expand to a command-token with that name (with \ in front, as it's a command token). I'm not sure what \expandafter does, however.
    – user218660
    Jun 19, 2020 at 15:43
  • @user218660 There is no string. Between \csname and \endcsname only character tokens should remain (after macro expansion). \expandafter expands the token after the immediately following one, in this case it jumps over \gobblebackslash and expands \string, which results in the five character tokens \•m•y•p•i. The name \string might be misleading, but it just converts a token to the character tokens that make up its name.
    – egreg
    Jun 19, 2020 at 15:55
  • Right. I meant "string" as in a sequence of tokens which are all just characters, as opposed to command tokens. So for example, even if you didn't need to remove the backslash, you would still need the \string in front of the \mypi (or #1 more generally)? And without \expandafter, the \gobblebackslash would delete \string, leaving you with \mypi•l•o•n•g, which has one non-character, which would cause an error?
    – user218660
    Jun 19, 2020 at 16:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .