Internally the definition of foreach will be saving the body of the loop in a macro so it is like (if looping over a,b,...
)
\def\body{%
\renewcommand*{\SomeCommand}[1]{\color{red}#1}% Using ## here eliminates the error.
\par\SomeCommand{\x}%
}%
}
\def\x{a}\body
\def\x{b}\body
...
That initial \def
(or \newcommand
if you prefer) will require a #
in the body to be entered as ##
. As shown above you would get an error on #1
as \body
doesn't take parameters it would have to be entered, as you found, as ##1
.
It is possible to define loops in such a way not to require this (for example it could use a token register rather than a macro for saving the body) but that is apparently not the case here.
Note that the need to double #
is unrelated to the fact that there is an inner macro definition. It is not that inner macros require ##1
to refer to the first parameter, it is simply that the inner macro definition requires the two tokens #
and 1
to refer to the first parameter and to get a #
into a macro body you need ##
. To see this consider a definition that doesn't have ##1
.
You can go
\let\hash=#
and \hash
will be let to #
but you can not define a macro as
\def\definehash{\let\hash=#}
as that generates
! Illegal parameter number in definition of \definehash.
You need ##
to refer to a literal #
in a macro definition. So it needs to be
\def\definehash{\let\hash=##}
You ask in comments why it needs four #
for a double nested definition. Again it is nothing special about the inner definitions, they never "see" ##1
by the time they are evaluated they just see a single #
. If you tried to define
\def\ddefinehash{\def\definehash{\let\hash=##}}
The definition would proceed without error but then if you try to execute \ddefinehash
you find that it just has a single #
in its definition and so you get the error as before:
! Illegal parameter number in definition of \definehash.
<to be read again>
}
l.12 \ddefinehash
So you need to get two #
into the definition of \definehash
and each of those has to be entered as ##
so you end up with
\def\ddefinehash{\def\definehash{\let\hash=####}}
Putting it all together:
{
\let\hash=#
}
{
\def\definehash{\let\hash=##}
}
{
\def\ddefinehash{\def\definehash{\let\hash=####}}
\ddefinehash
\definehash
\show\ddefinehash
\show\definehash
\show\hash
}
\bye
> \ddefinehash=macro:
->\def \definehash {\let \hash =####}.
l.15 \show\ddefinehash
?
> \definehash=macro:
->\let \hash =##.
l.16 \show\definehash
?
> \hash=macro parameter character #.
l.17 \show\hash
?
)
No pages of output.
Best Answer
On the left are TeX commands, on the right are LaTeX commands with similar functionality.
Macro definitions
\def
,\gdef
-->\newcommand*
,\providecommand*
,\renewcommand*
\long\def
,\long\gdef
-->\newcommand
,\providecommand
,\renewcommand
For commands with a scope, i.e. including grouping, LaTeX provides
\newenvironment
and\renewenvironment
.Mathematics
$ ... $
-->\( ... \)
withfixltx2e
, see Are ( and ) preferable to $$$ ... $$
-->\[ ... \]
, see Why is [ … ] preferable to $$\over
-->\frac
\atop
,\atopwithdelims
,\choose
-->\genfrac
and derivedamsmath
commands such as\binom
, see Why does amsmath print a warning about a foreign command\leqno, \eqno
-->equation
environment, optionalleqno
class oramsmath
optionTables
\cr
,\crcr
-->\\
,\tabularnewline
Spacing
\kern
,\hskip
-->\hspace
\vskip
-->\vspace
Positioning
\centerline
-->\centering
or thecenter
environment\raise
-->\raisebox
Miscellaneous
\uppercase
-->\MakeUppercase