joulev

% arara: pdflatex
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\msg_new:nnn { foo } { bar } { Some~text~about~#1~blah~blah }
\msg_info:nnn { foo } { bar } { \foo_bar }
\msg_info:nnn { foo } { bar } { something~which~is~not~a~cs }
\ExplSyntaxOff
\end{document}



Package foo Info: Some text about \foo_bar  blah blah

% Good
Package foo Info: Some text about something which is not a cs blah blah

% Expected
Package foo Info: Some text about \foo_bar blah blah


Did I miss something in the manual, or is this a bug in expl3?
Phelype Oleinik
This is not a category code issue, rather the timing of tokenisation. You'd see this same issue in this code:
tex
\def\test#1{\immediate\write16{\unexpanded{A #1 B}}}
\test{foobar}
\test{\foobar}


First, when \test is defined, it contains the tokens (I used · to separate them):
tex
\immediate·\write·1·6·{·\unexpanded·{·A· ·#1· ·B·}·}

Everything looks normal so far (except that #1 is not one single thing, but the two tokens macro parameter character # and the character 1, but for the sake of this example, that doesn't change anything). Notice that A· ·#1· ·B contains the 5 tokens: the letter A, blank space ​ ​, #1, blank space ​ ​, and the letter B.

When you use the macro \test with either foobar or \foobar, TeX replaces #1 by the argument and prints that. The difference appears because when TeX writes control sequence tokens it _prints_ an additional space after it, so you get A \foobar ​ B, but that's only for _printing_&thinsp;!  The token representation of that is still A· ·\foobar · ·B, which is the same 5 tokens you started with.

Your workaround with \string works because \string\foobar turns a control sequence token into the string of _character_ tokens \·f·o·o·b·a·r, which is not much different from x·f·o·o·b·a·r.
joulev
Oh, as it turns out, this has something to do with category codes[^1] again...


% arara: pdflatex
\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\msg_new:nnn { foo } { bar } { Some~text~about~#1~blah~blah }
\cs_generate_variant:Nn \msg_info:nnn { nnx }
\msg_info:nnx { foo } { bar } { \token_to_str:N \foo_bar }
\msg_info:nnn { foo } { bar } { something~which~is~not~a~cs }
\ExplSyntaxOff
\end{document}



% Both good:
Package foo Info: Some text about \foo_bar blah blah

Package foo Info: Some text about something which is not a cs blah blah


However I still don't know how an extra space is added, but no warnings or errors are issued at all...

[^1]: I don't use the word "catcode" because I fear the cats won't give me permission to do so :)

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.