13

From TeX by Topic, p. 111:

For certain applications, however, it is inconvenient that some of the plain macros are outer, in particular macros such as \newskip. One remedy is to redefine them, without the `outer' option, which is done for instance in LaTeX, but cleverer tricks are possible.

What are examples of such tricks for using \outer macros where they are not usually allowed?

1
  • 2
    'Don't use them' ;)
    – Joseph Wright
    Mar 19, 2020 at 11:11

5 Answers 5

15

As egreg said, the standard way is with \csname: as long as there is no \outer token at the time of the definition, you are safe.

So another possibility is, in a group, make the macro non-outer, define your macro, and then reset everything:

\begingroup
  \let\newdimen\relax
  \gdef\makedimenandgivevalue#1#2{%
    \newdimen#1%
    #1=#2\relax}
\endgroup

The problem with this version is that if you need to pass the \outer macro as argument to an auxiliary, you can't. A handier version is to define a non-outer wrapper to the \outer macro, then you can use it freely:

\edef\mynewdimen{\noexpand\newdimen}
%
\def\makedimenandgivevalue#1#2{%
  \mynewdimen#1%
  #1=#2\relax
}
13

The standard trick is \csname:

\def\makedimenandgivevalue#1#2{%
  \csname newdimen\endcsname#1%
  #1=#2\relax
}

Or \noexpand:

\edef\myproclaim#1#2\endmyproclaim{\noexpand\proclaim #1. \ignorespaces #2\par}

\myproclaim{Theorem}
This is better syntax.
\endmyproclaim

\proclaim Theorem.
This is worse syntax.

\bye

enter image description here

9

The famous \cleartabs, \settabs and \+ macros from plain.tex show one such trick (TeXbook p. 354):

\let\+=\relax % in case this file (plain.tex) is being read in twice
\def\sett@b{\ifx\next\+ \let\next=\relax % turn off \outerness
    \def\next{\afterassignment\s@tt@b\let\next}%
  \else\let\next=\s@tcols\fi\next}

...

\outer\def\+{\tabalign}
  1. \let\+=\relax is done before defining \sett@b in case \+ would already be an \outer token (otherwise, the \+ token in the replacement text of \sett@b would cause an error when \sett@b is defined).

  2. When the \ifx\next\+ test is true during normal usage of \settabs in the document, \next is an \outer token since in normal usage, \+ is \outer. Thus, Knuth does \let\next=\relax before redefining \next with \def\next{\afterassignment\s@tt@b\let\next}, otherwise the \next token at the end of the replacement text in this definition would cause an error.

4
  • +1 I love the irony ...
    – wave
    Mar 20, 2020 at 6:22
  • Regarding “famous”? Well, these macros are famous for being the most difficult to understand in plain.tex. :)
    – frougon
    Mar 20, 2020 at 8:19
  • 1
    no, just the fact that Knuth himself had to get rid of his own \outer definition due to the inconveniences coming along with it :D
    – wave
    Mar 20, 2020 at 8:30
  • Ah, that way. :-) (Security is almost always antagonist to convenience, you know... for some special TeXish definition of security here)
    – frougon
    Mar 20, 2020 at 8:35
8

For luatex, there is

\suppressoutererror = 1

which makes the entire issue go away.

You can use it globally or just locally in a group while you make the required definitions.

5

As already pointed out in egreg's answer:

If \outer-tokens are "hit" by \noexpand, they will be turned into \relax (only) for the next expansion:

\documentclass{article}

\outer\def\myoutermacro{My outer macro's definition.}

\def\FirstOfOne#1{#1}%

\newtoks\myscratchtoks

\begin{document}

% This does not work:
%
% \FirstOfOne{\myoutermacro}.
%
% These do work:

\expandafter\FirstOfOne\expandafter{\noexpand\myoutermacro}

\myscratchtoks\expandafter{\noexpand\myoutermacro}
\FirstOfOne{\the\myscratchtoks}

\edef\myscratchmacro{\noexpand\myoutermacro}
\FirstOfOne{\myscratchmacro}

\end{document}

You must log in to answer this question.

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