2

I read everywhere (e.g. https://en.wikibooks.org/wiki/TeX/let) that \let copies the content of a command into a new command.

My question is, why do we expect \let\comdwithtwoargs\@gobble makes \comdwithtwoargs have one argument?

\makeatletter
\newcommand{\cmd}[3]{%
    #1 #2 #3
    \let\cmd\@gobble
}
\makeatother

\cmd{abcdef} \cmd{abc}

In the example above, the code wouldn't run if I remove \let\cmd\@gobble. I don't understand the effect of \let and \@gobble and how they work.

Frank
  • 205
  • By \letting \cmd to \@gobble, the macro \cmd loses all of its original meaning (it is no longer a macro that takes two arguments or does anything), except to gobble the next argument. – Steven B. Segletes May 14 '20 at 17:34
  • 2
    hm, I'm not sure what you are trying to do, but if you define a command with 3 arguments, you should also use it with 3 argument, so \cmd{a}{b}{c}. – Ulrike Fischer May 14 '20 at 17:35
  • @UlrikeFischer That's why I am confused. Normally if we have a cmd with 3 args, it doesn't run without error if we use it like \cmd{arg1}, but it does run normally in the example. – Frank May 14 '20 at 17:47
  • @StevenB.Segletes Now I understand. Nothing special for @gobble. – Frank May 14 '20 at 17:48
  • 3
    Since \cmd actually has three arguments the code in the example does not really do what one would naively expect. In \cmd{abcdef} \cmd{abc} the first \cmd reads three arguments: Its first argument is abdcdef, its second argument is \cmd and its third argument is abc. Then it expands to #1 #2 #3, so we get abcdef \cmd abc, so the second \cmd which at that point has not been redefined grabs its three arguments, which are (because there are no { and }s) a, b and c in that order and itself expands to a b c. So you end up with abdcdef a b c. ... – moewe May 14 '20 at 18:03
  • 2
    well the first \cmd received the argument {abcdef} \cmd {abc} and outputs them unchanged (but without the braces. then the second \cmd gets the arguments a bc ` and puts them back in the output. I don't think it should matter if the \let is there or not, but perhaps you didn't show everything. – Ulrike Fischer May 14 '20 at 18:05
  • 3
    ... Then \cmd is \let to \@gobble. But this doesn't matter any more, since \cmd is not used after that. This is something wildly different from what one would expect if one were to call the macro with the correct number of arguments. If \cmd had been defined as \newcommand{\cmd}[1]{#1 let\cmd\@gobble} so that it just takes one argument \cmd{abcdef} \cmd{abc} would have resulted in just abcdef in the output: The first call \cmd{abdcdef} would have expanded to abcdef \let\cmd\@gobble and would have redefined \cmd to just eat its argument. Then \cmd{abc} produces no output – moewe May 14 '20 at 18:06
  • Ohh, commands can receive arguments even if the arguments aren't in braces, e.g. they can receive \something as an argument. I see. Thank you @UlrikeFischer and @moewe – Frank May 14 '20 at 18:07
  • 1
    Yes, TeX will always try and read the the specified number of arguments. Unbraced content will be grabbed token-by-token (https://de.overleaf.com/learn/latex/Articles/What_is_a_%22TeX_token%22%3F). – moewe May 14 '20 at 18:10
  • Thank you @moewe for referencing the article. That's really helpful and I really appreciate it! – Frank May 14 '20 at 18:13
  • 1
    Re tokens, see also https://tex.stackexchange.com/q/104023/35864 – moewe May 14 '20 at 18:15
  • Oh yeah. I gotta learn some basics. Thank you @moewe ! – Frank May 14 '20 at 18:23

1 Answers1

5

In comments it has been explained what is happening so let me take the opportunity to show how tex can show what it is doing, turning on \tracinngmacros and \tracingonline (so it logs on the terminal and not just in the log)

\documentclass{article}

\begin{document}


aaa % just to get font setup out of the way

{
\tracingonline=1
\tracingmacros=1

\makeatletter
\newcommand{\cmd}[3]{%
    #1 #2 #3
    \let\cmd\@gobble
}
\makeatother

\cmd{abcdef} \cmd{abc}

}

\end{document}

produces a terminal output

\cmd #1#2#3->#1 #2 #3 \let \cmd \@gobble 
#1<-abcdef
#2<-\cmd 
#3<-abc

\cmd #1#2#3->#1 #2 #3 \let \cmd \@gobble 
#1<-a
#2<-b
#3<-c

So in the first call to \cmd the three arguments are abcdef, \cmd and abc

so abcdef gets typeset then #2 #3 is \cmd abc so tex then logs the second call to \cmd this time the three arguments are a, b and c so it typesets a b c then defines \cmd to be \@gobble (twice) but the redefined \cmd is never called.

muzimuzhi Z
  • 26,474
David Carlisle
  • 757,742