Expansion is a complicated area of TeX programming. I'll try to explain the key primitives involved first, then try to come up with some examples.
The \expandafter
primitive expands the token after the next one. So
\expandafter\def\csname an-awkward-name\endcsname
will expand \csname
before \def
. So after one expansion the above turns into
\def\an-awkward-name
which will then do its thing. Life becomes more complex when you want to step further ahead, and it soon becomes very hard to track what is going on.
The \edef
> primitive does a full expansion of what is given as its argument (in contrast to \def
, which simply stores the input). So
\def\examplea{more stuff}
\edef\exampleb{Some stuff \csname examplea\endcsname}
will expand the \csname name\endcsname
to \examplea
, then expand that to leave a final definition of \exampleb
as 'Some stuff more stuff'.
Now, \noexpand
comes in by preventing \edef
from doing an expansion of the next token. So if I modify my above example to read
\def\examplea{more stuff}
\edef\exampleb{Some stuff \expandafter\noexpand\csname examplea\endcsname}
then what will happen is that the \edef
will execute the \expandafter
, which will turn the above effectively into
\def\examplea{more stuff}
\edef\exampleb{Some stuff \noexpand\examplea}
Now the \noexpand
will operate (disappearing in the process), leaving the definition of \exampleb
as 'Some stuff \examplea'.
We can use this ability to cut down on \expandafter
use, but there are a couple of other things to know. First, e-TeX includes an additional primitive \unexpanded
, which will prevent expansion of multiple tokens. Secondly, there are various special cases where you don't need quite so many \expandafter
statements. A classic example is from within \csname
, as this will do expansion anyway. So you'll see things like
\csname name\expandafter\endcsname\token
which will expand \token
before \name
.
Back to your example. In the first one, there isn't much to do: as the entire point is to have a dynamic name (#1
), doing an \edef
at point-of-definition doesn't really make sense. The closest one can get is something like
\edef\cohtheory{%
\noexpand\newcommand\expandafter\noexpand\csname foofunc\endcsname[1][*]{%
\noexpand\MakeUppercase{foo}^{##1}}%
}
What will happen here is that \newcommand
and \MakeUppercase
will be protected from expansion, and the \csname
will only expand once. (Tokens which don't have an expansion don't need protection, which is why things like '[1]' are simply included as is.) Of course, this is something of a 'toy' as all it does is create a fixed \foofunc
.
For your second example, you could instead to
\begingroup
\edef\temp{%
\endgroup
\noexpand\command
{\unexpanded\expandafter{\argone}}%
{\unexpanded\expandafter{\argtwo}}%
}
\temp
I'm using a couple of extra ideas here. First, the group is used so that \temp
is not altered anywhere other than where I'm using it. The \endgroup
primitive will do nothing inside the \edef
, and so will still be there to close the group when \temp
is used. Secondly, \unexpanded
works like a toks, and so will respect the \expandafter
after it but before the {
. This cuts down on an unnecessary \expandafter
.
There are more wrinkles to this, and often there are several equally-efficient and clear methods. You are best off posting specific examples, and seeking advice on how they might be achieved.
You can make a dummy \def
inside \detectmodifiers
which will be affected by any of the mentioned modifiers if its at the beginning of the macro. Then you can test for the modifiers to build the if
-switches. You can use \meaning
on a dummy macro which contains the \outer
, \long
and \protected
modifiers as string which can be extracted and turned into macros again using \scantokens
.
One challenge would be \global
: you need to make the assignment in a group and check if it is still the same after the group.
You should use the if
-tree you have but rather define a macro \themodifiers
which is then put in front of \def
:
\def\themodifiers{\protected\global}
... \themodifiers\def...
.
Here some proof-of-concept code. I remembered that the "modifiers" are called prefixes, so I changed the macro names. The prefixes are stored in the \theprefixes
macro which can be used in front of \def
. The \global
prefix however is special and can't be read like this. I tried to define the \dummy
macro inside a group and use \global\let\gdummy\dummy
so that I can test if both are still the same after the end of the group. The problem is: a \begingroup
or {
isn't allowed before the \def\dummy
:-(
You should change the names of some macros to prevent name clashes.
\documentclass{article}
\makeatletter
\def\macroother{macro}
\@onelevel@sanitize\macroother
\makeatother
\expandafter
\def\expandafter\returnprefixes\expandafter#\expandafter1\macroother#2\relax{%
\scantokens{\def\theprefixes{#1}}%
}
\def\detectprefixes{%
\def\dummy{}%
\expandafter\returnprefixes\meaning\dummy\relax
}
\def\otherdef{%
\detectprefixes
% other code
\theprefixes\def
}
\global\long\outer\protected\otherdef\mymacro{mystuff}
\show\mymacro
\begin{document}
\end{document}
Best Answer
\outer
isn't used in LaTeX2e and I'm not aware of any packages that do, either (there are probably some, though). However, I've come across occasion to think it might sometimes be a good idea.\outer
prevents a macro from being used inside any other macro. But when is this even desirable? Well, consider the use of\verb
: because it changes catcodes, and catcodes are frozen when tokenization occurs,\verb
can never be (reliably) used inside any other macro. For examples, this will not work:Now,
\verb
contains its own processing to give a suitable error message in this case anyway, but there are other packages that define commands that use catcode-mucking to do their work. For examples, some indexing commands and, say,\url
, can give bad output if they're used inside macros. In theory, you could use\outer
to enforce their use in running text only, but this isn't done very often.Note also that eTeX gives
\scantokens
which relieves many of the restrictions of only being able to change catcodes before tokenization occurs. So\outer
is less useful these days from that point of view.