57

Assume that I want to define a new environment that is a variant of an existing one. For example, I seek an italicquote environment that acts like the quote environment but displays its contents in italic. The approach endorsed in section A.1.3 of the LaTeX Companion is to write the internal environment as one would use it in the text body, i.e.

\newenvironment{italicquote}{%
  \begin{quote}%
  \itshape
}{%
  \end{quote}%
}

However, in this answer to Defining my own description environment Martin Scharrer advocates writing the internal environment into its plain form, i.e., transforming my example into

\newenvironment{italicquote}{%
  \quote
  \itshape
}{%
  \endquote
}

His reasoning:

The internal environment is written into the plain form [...] to avoid confusing error messages when [\end{italicquote}] is missing. In this case the last \begin would be the one of the internal macro and its name would be printed in the error message instead of the one written in the source file. This isn't a problem for your own small environments, but important if they are used by other people.

Is the second way of defining "derived" environments to be preferred without exception? If yes, why did the LaTeX Companion use the first way? If no, in what situations should one prefer to write \begin{quote} ... \end{quote} in my example environment?

3
  • 1
    Just to point that out: The @ notification doesn't work in questions and answers, only in comments and chat messages. Mar 31, 2011 at 18:28
  • My opinion in general: use the documented/officially recommended approach, as this is what other people are familiar with. Maintainability and readability of code comes first. However, in this case we see that the unusual way may have benefits—if you find them really important, then use this approach, but add a comment explaining what is being done. Mar 31, 2011 at 18:57
  • 3
    @Andrey: in a nutshell, you need to know the rules in order to know when it's OK to break them. :-) Mar 31, 2011 at 19:18

1 Answer 1

53

The reason I got told to use the "plain form" for inner environments was, as already quoted in the question, that if the normal \begin/\end form is used and the last \end{<outer env>} is missing or misplaced the error message includes the name of the last inner \begin{<env>}. A user might not be aware that the outer environment uses this environment internally and can get confused. Because it can be part of several used environments the error doesn't give that much information where to look (except the line number, which might be all what you need if you stick with one \begin per line).


Let us look at the definitions of \begin and \end to see what the exact differences between the two forms are:

\def\begin#1{%
  \@ifundefined{#1}%
    {\def\reserved@a{\@latex@error{Environment #1 undefined}\@eha}}%
    {\def\reserved@a{\def\@currenvir{#1}%
     \edef\@currenvline{\on@line}%
     \csname #1\endcsname}}%
  \@ignorefalse
  \begingroup\@endpefalse\reserved@a}

So \begin checks for if #1 (the environment name) exists as macro and reports an error if not. Otherwise the current list and the name is saved. The latter as \@currenvir. This is done inside a group opened with \begingroup. The @ignore switch is for ignoring spaces afterwards and the @endpe is "to suppress the paragraph indentation in text immediately following a paragraphmaking environment" (source2e).

\def\end#1{%
  \csname end#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}

The \end macro executes \end<envname>. It then checks using \@checkend if the given name is equal to the one used by the last opened \begin. If both aren't equal an error message is printed. It then executes the \@doendpe code to suppress paragraph indentation if enabled and closes the group. Spaces might then be ignored if that was enabled.


Let's look at the differences: As seen in the above code description the things which are done in addition if the normal LaTeX form is used are:

  1. The existence is checked.
  2. A group is added.
  3. The environment name is saved.
  4. The number of the line where the environment starts is saved.
  5. Spaces can be ignored afterwards.
  6. A paragraph indention can be avoided.

Do we need these things for inner environments?:

  1. Not really, it should be known if the inner environment exists or not.
  2. There is already a group added by the outer environment and almost never an extra group is needed. One exception are verbatim and other special environments which can't be nested without extra precaution anyway. There might be some non-verbatim environments which require an inner group for themselves, but these should not rely on the one added by \begin/\end, but add it explicitly. Anyway, the group could be added manually if required.
  3. That's the one thing which should be directly avoided.
  4. Already saved by the outer environment.
  5. Can be done by the outer environment and is needed because \end{xxx} ends with } so it doesn't removes spaces. The plain form \endxxx however does and therefore doesn't require that. An explicit \ignorespaces could be added if someone insists.
  6. This point is one of the main important ones, which I just found out about while writing this answer: the fact that the paragraph should be indented or not. This seems to be set to true in the begin-code of some environments and is executed and set back to false inside \end. So if the plain version is used it will move to the outer \end which might or might not be the right thing. I would recommend to set the switch @endpe manually at the end to the proper value to avoid issues.

Conclusion:

There should be no issues with using the plain form for inner environments as long as the expected paragraph indention is handled. They have the benefit of generating meaningful error messages and are also slightly faster and do not generate (normally) unnecessary subgroups. Special care might be required for special inner environments.

4
  • 12
    Man that's a good answer! Mar 31, 2011 at 21:16
  • 1
    Regarding the {verbatim} environment, at least with the verbatim package, it is wrong to use \begin{verbatim} inside the start code of a new environment, because the verbatim will pick up the wrong \@currenvir and fail to terminate. This is of course what you meant, but I thought it should be spelled out for the casual reader. I also don't see why the extra group would be necessary here, since \begin{verbatim} is like \begingroup\verbatim, while inside another environment, there's just more stuff after the \begingroup; the \verbatim comes last, so it sets its own context.
    – Ryan Reich
    Dec 16, 2011 at 8:43
  • @RyanReich: Yes, that's right. Environments like verbatim were what I meant with the last sentence. Some listings code works similar. Then there is lrbox which needs the \begin and \end because it closes the environment group at the beginning to avoid a local definition of the box register. Dec 16, 2011 at 9:01
  • 2
    \begin and \end have changed in the LaTeX kernel since this answer was written. If you don't call them for the inner environment, its \BeforeBeginEnvironment, \AtBeginEnvironment, \AtEndEnvironment and \AfterEndEnvironment hooks won't be run. AFAIK, the hooks were added in 2020; see texdoc lthooks.
    – frougon
    Jun 12, 2022 at 8:45

You must log in to answer this question.

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