48

Knuth hid a special rule for delimited arguments in exercise 20.5 of the TeXbook.

If the very last character of the parameter text is #, so that this # is immediately followed by {, TeX will behave as if the { had been inserted at the right end of both the parameter text and the replacement text.

This means that a macro can be defined as,

\def\a#1#{#1}

calling it as \a 10 will give a runaway argument error whereas calling it as \a{12}, will compile with no trouble.

I struggled to find a practical application for such macros even after looking at TeX by Topic, TeXbook and LaTeX source.

Here is my take on it, create some commands to typeset and do some calculations for fractions, as for example those found in basic arithmetic texbooks. You type this,

\[\FRAC ADD{3}{8}+{1}{7}\]
\[\FRAC SUB{5}{8}-{1}{7}\]
\[\FRAC MUL{5}{8}x{13}{1201}\]

and you get this:

enter image description here

Here is the code,

\documentclass{article} 
\begin{document}
%% macro factory
\def\FRAC#1#{\csname #1\endcsname}
%% add
\def\ADD#1#2+#3#4{%
  \frac{#1}{#2}+\frac{#3}{#4}=
  \frac{\the\numexpr(#4*#1)+(#3*#2)}{\the\numexpr#2*#4}
}
%% subtract
\def\SUB#1#2-#3#4{%ok top
  \frac{#1}{#2}-\frac{#3}{#4}=
  \frac{\the\numexpr(#4*#1)-(#3*#2)}{\the\numexpr(#2*#4)}
}
%% multiply
\def\MUL#1#2x#3#4{%
  \frac{#1}{#2}\times\frac{#3}{#4}=
  \frac{\the\numexpr(#1*#3)}
  {\the\numexpr#2*#4}
}
%% testing
\[\FRAC ADD{3}{8}+{1}{7}\]
\[\FRAC SUB{5}{8}-{1}{7}\]
\[\FRAC MUL{5}{8}x{13}{1201}\]
\end{document}

Are there any practical applications for such macros? Are there any special precautions one should take? Why would Knuth include this facility in the first place?

3

6 Answers 6

20

This trick of catching until the first open brace can be used in many situations.

  • As other posters said, it allows to catch an optional argument expandably if it is not the last. It is possible in principle to get this to be fully robust with respect to nesting, but not implemented yet.

  • It can be used to parse the body of a definition provided by the user, to change it to fit your purposes while keeping a natural syntax. (More on parsing def below.)

  • I've used this trick primarily to parse a token list expandably without losing any brace. For instance,

    • to expandably uppercase or lowercase a given string (see this answer)

    • to fully expand a token list expandably (almost as well as the luatex primitive \expanded (see this answer)

    • to expand tokens selectively, or in the reverse order

    • to write a primitive macro expander (i.e. take a file, and expand user-defined macros)

    so basically any situation where you need to be careful with braces, but cannot use \futurelet.

This trick only works if there is only one character with catcode 1 (begin group character). Also, we need to be able to put a sentinel at the end of the token list that we are manipulating: otherwise, in the absence of opening brace, we would get a runaway argument.

On parsing a definition: say that you want to give the user an easy way of defining a macro which possibly takes arguments, and always produces a boxed math result. Say that you also want the parameter text to be arbitrary. Either you let the user do everything, or you parse the definition using the trick you ask about.

%non-user-friendly
\def\foo_#1^#2#3#4{\fbox{$\sum_{#1}^{#2} \frac{#3}{#4}$}}

%more user friendly (perhaps)
\boxeddef\foo_#1^#2#3#4{\sum_{#1}^{#2} \frac{#3}{#4}}

To do that:

\documentclass{article}
\makeatletter
\def\boxeddef#1#2#{\boxeddef@aux{#1}{#2}}
\def\boxeddef@aux#1#2#3{\def#1#2{\fbox{$#3$}}}
\makeatother
\begin{document}
%\def\foo#1#2#3#4{\fbox{$\sum_{#1}^{#2} \frac{#3}{#4}$}}
\boxeddef\foo_#1^#2#3#4{\sum_{#1}^{#2} \frac{#3}{#4}}
\[
\foo_{a}^{b}{C}{D}
\]
\end{document}
21

The #{ trick can allow to make macros which behave somewhat like \hbox{...}, in the sense that they can have, for example, verbatim inside their argument (also, the argument is not read beforehand). There’s a nice example in the Tugboat article The TeX Hierarchy (Volume 15, 1994, p. 7-9):

Programming style comparison

Compared to the Wizard’s version, the Guru’s use of #{ makes sure that the character eaten by \let\next= will always be a brace, never something else.

10
  • 1
    @Philippe: Just to make sure I'm getting it: the \let\next= just serves the purpose to eat the opening { of \bold{...}, correct? Mar 14, 2011 at 22:22
  • 1
    @Hendrik: yes, and the \bgroup is here to match the closing brace of \bold{...}. Mar 14, 2011 at 22:28
  • 1
    @Philippe Goutet ... Capo di Guru : digs out a the only article in TUGboat listing an example of #{, thanks :) Mar 15, 2011 at 13:32
  • 1
    I can't upvote this enough. However, I don't understand why the Guru's version has a space after the =.
    – Ryan Reich
    Jun 21, 2011 at 16:43
  • 1
    I wonder what is happening with: \def\bold#{\bgroup\bf\let\next= }\halign{\bold{#}\crcr test}\bye.
    – morbusg
    Aug 24, 2012 at 16:51
14

an example from latex.ltx

\def\usepackage#1#{%
  \@latex@error
    {\noexpand \usepackage before \string\documentclass}%
    {\noexpand \usepackage may only appear in the document
      preamble, i.e.,\MessageBreak
      between \noexpand\documentclass and
      \string\begin{document}.}%
  \@gobble}

with the argument setting you can handle optional arguments, eg \usepackage[foo]{bar} without defining the different cases

9

Reading everything up the opening { as argument like \def\A#1#{...} would do, it is not very common, but useful when you want to read optional arguments of macro which normal argument must start with { anyway. This can be very useful in cases when the macro should be fully expandable and therefore \futurelet (used by \@ifnextchar) can't be used.

Funnily, I just started to use this TeX feature this week: In my up-coming package 'filemod' I define expandable and non-expandable macros to read and compare file modification dates. The expandable implementation of \filemodNewest takes an optional argument and list of file names {{filename1}{filename2}...{filename3}} and expands the the name of the newest file. The #{ syntax is used to read the potential optional argument (a number in this case):

\def\filemodNewest#1#{%
  \expandafter\expandafter
  \expandafter\@filemodNewest
  \csname
    @%
  \ifx\@nnil#1\@nnil
    first%
  \else
    second%
  \fi
    oftwo%
  \endcsname
    {[\filemodcmpdefault]}%
    {#1}%
}

It should be noted that this works only for simple optional arguments which do not include braces. This excludes e.g. complex PGF keys etc.

Also the etextools defines another way of expandable macros with optional arguments using eTeX \detokenize.

4
  • it is possible to extend this expandable parsing of optional arguments in a fully robust way, as long as the last argument is a brace group (assuming that there is only one character with catcode 1). That's on my todo list for Joseph's xparse. Mar 13, 2011 at 21:21
  • @Reader: If you find the use of \csname ... \endcsname funny, have a look at the rest of the code where \csname is used to recursive expand parts of the compare loop :-) Mar 13, 2011 at 21:24
  • @Bruno: xparse is not mine: I just revisited the code from stuff others had written! (See also my comments about the limitation of { and on trailing optional arguments: I suspect \futurelet is the only truly robust approach, but am happy to be proved wrong.)
    – Joseph Wright
    Mar 13, 2011 at 21:47
  • @Joseph: After studying TeX's mouth for a while, I believe that you are right on this. The current xparse chokes in some cases with optional argumentsdelimited by implicit characters. More on this by email. Mar 14, 2011 at 22:41
5

I just used this construction in my expandable sanitizer: Can one define an expandable command that removes control sequences from its argument?. The purpose there is so that I can parse some arbitrary (well-formed) input for the first group it contains, without actually entering the group. Without \futurelet or \catcode changes, it's impossible to grab a single brace token, but this way, I can expand up until a group, leaving the braces there, and then continue processing with the sure knowledge that the next thing on the menu is a group. It has exactly the same purpose as \futurelet for this one token.

1
  • I read your answer in the post you quote. It's an amazing piece of code. Nov 9, 2011 at 8:09
4

I use this possibility in the next case. I can't use delimiters like () because the parenthesis are nested. With

\documentclass{minimal}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc} 

\def\macro#1#{%
  <#1>\par
  \macrobis
}
\def\macrobis#1{and <#1>}

\begin{document}
\macro(exp(1),ln(2)){A}
\end{document}

The first #1 catches (exp(1),ln(2))

enter image description here

3
  • As I recently got told here xparse is able to parse () or [] arguments in an way so that they can be properly nested. But for simpler macros this way is much faster. Mar 13, 2011 at 21:32
  • @Martin Yes I know and you are right. The method is more direct and much faster like you said. My english language is poor so I have some difficulties to explain exactly how useful is this method. Mar 13, 2011 at 21:41
  • @Martin: One issue with the # method is that it only works for whatever token was catcode 1 at definition time. Not a problem for almost all applications, but if we get xparse right as part of LaTeX3 then this is something that might be important. It's also no good for something that requires the last argument is optional (for example \break).
    – Joseph Wright
    Mar 13, 2011 at 21:46

You must log in to answer this question.

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