7

I was surprised to discover that when I create an environment in LaTex, a command of the same name is created. For example:

\documentclass{minimal}

\newenvironment{foo}{Foo: }{}

\begin{document}

\foo{bar}

\end{document}

produces the output "Foo: bar" as you can see in this Overleaf example. In addition to Overleaf, it also works in Texpad, so it seems widespread.

My first question is: where can I find this documented? It doesn't pop out in any of the places I usually look.

Furthermore, it doesn't seem to be widely known. For example, when you use \newcommand to define a command, it appears as suggestion in code-completion. But when you use \newenvironment, it only appears in code-completion suggestions for \begin{, not for \ (i.e., not as a command).

It seems fantastically useful: I'd love to use \align*{...} rather than \begin{align*}/\end{align*}

Second question: am I missing something? Is there some reason that this is problematic?

Thanks!

Edit: Thanks for the thoughtful detailed answers! To boil it down, the \newenvironment command creates two commands: in this case \foo and \endfoo which, generally speaking, contain your specified code. When you do \begin{foo} and \end{foo}, it not only surrounds your code with those commands, it also surrounds it with \begingroup and \endgroup, similar to wrapping the whole thing in braces. I have edited my overleaf example above for and MWE of how this fails with a user-defined command. I also found this answer helpful.

5
  • 4
    I was surprised to learn it, as well, when I asked this question: tex.stackexchange.com/questions/116670/duplicating-environments Oct 9 '20 at 14:45
  • 1
    When you declare a new environment foo you are basically defining two macros \foo and \endfoo. I'm sure there is some other Q/A on the site. align is somewhat different.
    – campa
    Oct 9 '20 at 14:46
  • 2
    There are important differences between macros and enironments: 1) environments are group surrounded, not so macros, 2) 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 are absorbed on the fly, subject to changes that have transpired in the course of the environment. 3) 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). Oct 9 '20 at 14:50
  • 2
    I shamelessly refer to this answer of mine for a rough explanation of what \begin and \end do.
    – campa
    Oct 9 '20 at 15:25
  • 2
    it's not that it's unproblematic, it simply doesn't work. especially for environments such as align that grab their body. Oct 9 '20 at 17:40
8

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.

enter image description here

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.

4
  • Sorry for the long delay, I hit an internet dead zone, and then... life. Thanks for this answer!
    – Nat Kuhn
    Oct 26 '20 at 21:21
  • @NatKuhn Don't worry! I got green ticks years after the answer! :-)
    – egreg
    Oct 26 '20 at 21:38
  • "Getting green ticks" sounds very unpleasant, at least on this side of the pond ;-)
    – Nat Kuhn
    Oct 26 '20 at 21:45
  • @NatKuhn Here it's pleasant, particularly if David doesn't get one for his competing answer. ;-)
    – egreg
    Oct 26 '20 at 21:54
7

Converting my comment into an answer.

There are important differences between macros and environments:

  1. environments are group surrounded, not so with macros.

  2. 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.

  3. 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 \fboxed 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 \fboxed. 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} 

enter image description here


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}
1
  • Thank you for this answer, wish I could accept more than one! And sorry for the delay, I was out of internet for several days and then swamped.
    – Nat Kuhn
    Oct 26 '20 at 21:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.