Environments create commands? What am I missing?
It's not fantastically useful, sorry. Try
\documentclass{article}
\begin{document}
This is some text flush left apart from indentation
\center
This should be centered
\endcenter
and this shouldn't be
\end{document}
and you'll get the following output. You might be surprised, but you shouldn't be.
What happens? Certainly, doing \newenvironment{foo}{...}{...}
defines \foo
and \endfoo
, because TeX only knows macros.
However, \begin{foo}
is not the same as \foo
and \end{foo}
is not the same as \endfoo
. Indeed, if we look at the definition of \begin
, we see
% latex.ltx, line 7211:
\DeclareRobustCommand*\begin[1]{%
\UseHook{env/#1/before}%
\@ifundefined{#1}%
{\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
{\def\reserved@a{\def\@currenvir{#1}%
\edef\@currenvline{\on@line}%
\@execute@begin@hook{#1}%
\csname #1\endcsname}}%
\@ignorefalse
\begingroup\@endpefalse\reserved@a}
and we realize that \csname #1\endcsname
, which in the case of \begin{foo}
will become \foo
, comes rather late in the processing. If we follow the “false” branch, the one that's used when the environment is indeed defined, we eventually get
\@ignorefalse\begingroup\@endpefalse
\def\@currenvir{foo}%
\edef\@currenvline{<some line number>}%
\@execute@begin@hook{foo}%
\foo
If you just use \foo
, you miss all the preceding code. It's not important that you understand the code, but it's essential that you realize that it's there!
There is similar bookkeeping when \end{foo}
is processed, in particular \endgroup
is emitted to balance the previous \begingroup
that you see in the code above.
Believe it or not, it is this \endgroup
that makes a big difference in the center
example I showed.
By the way, amsmath
environments such as align
behave even differently and calling \align...\endalign
will break so many things!
There is a case when \foo
and \endfoo
can be used quite safely, for instance for defining a new environment based on foo
. But leave this to when you'll be an expert of LaTeX coding. Meanwhile, use \begin{foo}...\end{foo}
and be happy.
These are the errors I get if I add \usepackage{amsmath}
and try
\align a&=b \endalign
Here they are:
Runaway argument?
a&=b \endalign
! Paragraph ended before \document was complete.
<to be read again>
\par
l.7
?
! Missing $ inserted.
<inserted text>
$
l.7
?
! Missing \endgroup inserted.
<inserted text>
\endgroup
l.7
?
! Display math should end with $$.
<to be read again>
\par
l.7
?
No output whatsoever. Not for the faint of heart.
Converting my comment into an answer.
There are important differences between macros and environments:
environments are group surrounded, not so with macros.
a macro tokenizes its argument at the outset, so nothing that happens inside the macro can affect, for example, the catcodes of the tokens in the argument. In the environment, tokens from the input stream are absorbed on the fly, subject to changes that have transpired in the course of the environment.
environments allow trailing code to be executed, once the input stream is exhausted (and the trailing code is needed to close out the group opened by environment).
The MWE below demonstrates all three of these differences.
The tokcycle
package allows one to cycle through the tokens of an argument or input stream and process them according to specified directives. The package provides both macro and pseudo-environment forms. By "pseudo-environment", I mean an environment requiring the use of \macro...\endmacro
syntax, rather than the more familiar \begin{envname}...\end{envname}
syntax.
In the MWE, I directly typeset (rather than store in a token register) the tokcycle
-processed input. The processing is as follows: any token will be echoed to the output, except cat-7 ^
tokens, which will be output as an \fbox
ed string. When the process is complete, the value defined by \aftertokcycle
is typeset, here being pre-set to an exclamation point !
I employ this processing using both macro and environment approaches to the following input: \chcat This is a ^ test
, where \chcat
is a macro that changes the catcode of ^
to a value of 12
.
Item 1 is demonstrated by showing that, following the macro exit, the catcode of ^
remains at 12
, whereas following the environment invocation, it returns (because of grouping) to its prior value of 7
.
Item 2 is demonstrated by noting that only the ^
in the macro gets \fbox
ed. This is because, as part of a macro argument, the ^
is tokenized as catcode 7
, regardless of what changes transpire in the course of executing the argument. In the environment alternative, the ^
is not boxed, because it has been tokenized only after the catcode of ^
has been changed to 12
in the course of executing the input stream.
Item 3 is demonstrated by the absence of the trailing !
in the environment version. Why? Because the environment form executes its own trailing code through the same macro employed by the \aftertokcycle
invocation. Thus, the prior invocation of \aftertokcycle
carries no sway over the environmental form, which uses its trailing code to redefine that variable. The macro form does not execute any trailing code, so a predefined \aftertokcycle
still holds sway.
\documentclass{article}
\usepackage{tokcycle}
\def\chcat{\catcode`^=12}
\begin{document}
\Characterdirective{\tctestifcatnx^#1{\fbox{\string#1}}{#1}}
\Groupdirective{\processtoks{#1}}
\Macrodirective{#1}
\Spacedirective{#1}
\aftertokcycle{!}
Macro form:\\
\begingroup
\tokcyclexpress{\chcat This is a ^ test}
Caret catcode: \number\catcode`^
\endgroup
Environment form:\\
\tokencyclexpress \chcat This is a ^ test\endtokencyclexpress
Caret catcode: \number\catcode`^
\end{document}
For the geek: The macro and environment forms of tokcyle
used in this MWE both rely on the same underlying "raw" pseudoenvironment. The code to these interface forms may help to clarify why the macro acts like a macro and the pseudo-environment acts like an environment:
Macro Form (xpress interface):
% XPRESS-INTERFACE MACRO FORM
\long\def\tokcyclexpress#1{\tokcycrawxpress#1\endtokcycraw}
Pseudo-environment form (xpress interface):
% XPRESS-INTERFACE ENVIRONMENT FORM
\def\tokencyclexpress{\begingroup\let\endtokencyclexpress\endtokcycraw
\aftertokcycle{\the\cytoks\expandafter\endgroup\expandafter\tcenvscope
\expandafter{\the\cytoks}}\tokcycrawxpress}