2

In the MWE:

\documentclass{article}
\setlength{\fboxsep}{0pt}
\begin{document}

\ExplSyntaxOn
\cs_new:Npn \foo:nn #1#2
  {
    \makebox[#1][s]{#2}
  }
% \cs_new:Npn \bar:nn #1#2 { \foo:nn #1#2 }
\let \bar:nn \foo:nn
\fbox{\foo:nn {3cm} {a~b~c~d}}\par
\fbox{\bar:nn {3cm} {a~b~c~d}}
\ExplSyntaxOff

\end{document}

If I use \cs_new:Npn instead of \let, it will throw an "illegal unit of measure" error. Why? How can I fix this?

7
  • 1
    You're missing the braces to the arguments: \cs_new:Npn \bar:nn #1#2 { \foo:nn {#1}{#2} }. But, since you mean \let, you probably really want \cs_set_eq:NN.
    – gusbrs
    Apr 16 at 2:51
  • Since I miss the braces, \bar:nn {3cm}{...} will pass the single token 3 to \foo:nn as its first parameter and the error occurs. Right? @gusbrs
    – Stephen
    Apr 16 at 3:06
  • It will grab the first single token. So, yes, as far as I get it, \foo:nn, when called from \bar:nn, will see the first argument as 3 and the second as c.
    – gusbrs
    Apr 16 at 3:19
  • Since \makebox is not fully expandable, \foo:nn neither, thus it's better to define \foo:nn by \cs_new_protected:N(p)n. Apr 16 at 4:37
  • How to judge that \makebox isn't fully expandable? @muzimuzhiZ
    – Stephen
    Apr 16 at 5:53

1 Answer 1

4

It's a problem of TeX syntax:

\cs_new:Npn \foo:nn #1#2 { ... }

is how you define \foo:nn. But when you call it, you need to do

\foo:nn {<argument 1>}{<argument 2>}

and the braces can be omitted if the argument consists of a single token.

In your attempt, from \bar:nn {3cm}{abcd} you get

\foo:nn 3cmabcd

so #1 is 3 and #2 is c, resulting in

\makebox[3][s]{c}mabcd

which is definitely not what you want. With

\cs_new:Npn \bar:nn #1#2 { \foo:nn {#1}{#2} }

you obtain the desired thing.

Observed that \let should not be used where \cs_new_eq:NN is the correct call, let's compare the following calls:

  1. \cs_new:Npn \bar:nn #1#2 { \foo:nn {#1}{#2} }
  2. \cs_new_eq:NN \bar:nn \foo:nn

Are there any differences? Plenty. With the first call, \bar:nn will use the meaning of \foo:nn that's current at call time; with the second call, \bar:nn will use the meaning of \foo:nn current at definition time. So you need to know why you do such a definition and do the appropriate choice. If you're certain that \foo:nn never changes meaning, the two calls are almost equivalent: not completely the same, because with 1 \bar:nn requires one expansion step more than with 2.

Note. I disregarded a few aspect that aren't relevant for the issue, but they're important.

  1. Try and follow the expl3 naming conventions: both \foo:nn and \bar:nn are bad names.

  2. Functions that employ unexpandable functions/macros such as \makebox should be “protected”:

    \cs_new_protected:Npn \stephen_foo:nn #1#2 { \makebox[#1][s]{#2} }
    

    would be better.

You must log in to answer this question.

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