1

As far as I understand, when I specify

\newenvironment{env}{
  start
}{
  end
}

what LaTeX actually does is to define two macros

\env -> start 
\endenv -> end

so that

\begin{env}
  middle
\end{env}

is resolved into something like

{
  \env
  middle
  \endenv
}

  • Is my perception correct and complete?
  • Are there other things \newenvionment, \begin and \end do?
  • Could I create the environment without \newenvironment just by defining \env and \endenv? Are there situation that may benefit from this?
  • Is it safe to use \env and \endenv without \begin and \end? For example, to avoid the grouping.
  • How does xparse's \NewDocumentEnvironment differ?

Many questions, all connected by one request: Please explain how environments and the related commands work.

XZS
  • 2,953
  • Albeit interesting, I think this has been asked and answered elsewhere on the site. – egreg Sep 23 '15 at 21:11
  • With xparse you can use the parameters #1 etc. even in the end code .... and environments keep track of the current environment with \def\@currenvir{env} for example. –  Sep 23 '15 at 21:12
  • @egreg feel free to direct me there. I already searched for some variants of the question without any luck. – XZS Sep 23 '15 at 21:13
  • Somehow related: http://tex.stackexchange.com/questions/254549/latex-programming-inheritance-with-newcommand-newenvironment-renew-etc/254550#254550 –  Sep 23 '15 at 21:15
  • @ChristianHupfer I am interested in how xparse does these things and whether they introduce any performance penalty compared to the classic \newenvironment. So if you know, I would appreciate an answer. – XZS Sep 23 '15 at 21:15
  • @XZS: xparse does very sophisticated things, using the new LaTeX 3 language approach from expl3. It's not easy to explain this –  Sep 23 '15 at 21:18

2 Answers2

4

Only a partial answer:

  • Environments with \newenvironment do in fact define \env and \endenv (if used with env as argument)

    However \env...\endenv is not group safe, see the setting of the length variable in the lower example.

  • It's not possible to define \newcommand{\otherenv} and \newcommand{\otherendenv}, since this will result in an error:

! LaTeX Error: Command \endotherenv already defined. Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.

I've asked a similar question about \end... macros about one year ago: Are \end.... macro names reserved in LaTeX2e?

However, it's possible to say \def\otherenv and \def\endotherenv. This is fact how many LaTeX2e environments are defined in the LaTeX core or in packages -- for example enumerate is \def\enumerate and \def\endenumerate and not defined using \newenvironment{enumerate}


\documentclass{article}

\newenvironment{env}{}{}
\newlength{\mylength}
\setlength{\mylength}{10pt}

\begin{document}


\begin{env}
\addtolength{\mylength}{20pt}
\end{env}

Result after: \the\mylength $\longrightarrow$ safe!

\env

\addtolength{\mylength}{20pt}

\endenv

Result after: \the\mylength $\longrightarrow$ not safe!

% Now some grouping:    
{
\env

\addtolength{\mylength}{20pt}

\endenv
}

Result after: \the\mylength $\longrightarrow$ safe again!

\end{document}

enter image description here

In addition, an environment defined with \newenvironment is 'self-aware' (well ;-)) -- it knows the current environment name, but only if \begin{env}...\end{env} is used, not with \env...\endenv or {\env...\endenv}

See the second example:

\documentclass{article}

\makeatletter
\newcommand{\ShowEnvName}{%
Current environment:  \@currenvir

}
\makeatother


\newenvironment{env}{}{}

\begin{document}
\begin{env}
\ShowEnvName  : Should be \texttt{env}
\end{env}

\env
\ShowEnvName  : Presumed to be \texttt{env}, but is \texttt{document}
\endenv

{
\env
\ShowEnvName  : Presumed to be \texttt{env}, but still is \texttt{document}
\endenv
}


\env
{
\ShowEnvName  : Presumed to be \texttt{env}, but still is \texttt{document}
}
\endenv


\end{document}

It shows the outer environment name as soon as there's no \begin...\end pair -- that's what \begin...\end do --> setting the \@currenvir macro.

enter image description here

From latex.ltx (or see texdoc source2e) the definition of \begin and \end:

\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}
\def\end#1{%
  \csname end#1\endcsname\@checkend{#1}%
  \expandafter\endgroup\if@endpe\@doendpe\fi
  \if@ignore\@ignorefalse\ignorespaces\fi}
\def\@checkend#1{\def\reserved@a{#1}\ifx
      \reserved@a\@currenvir \else\@badend{#1}\fi}

\begin checks first whether the environment is defined at all and gives an error in the false branch. If successful, the @currenvir variable is set to the environment and \csname #1\endcsname, i.e. \env is called and a \begingroup started.

\end checks whether the correct environment is closed at the moment, i.e. \begin{env}...\end{otherenv}\end{env} would be an error if otherenv hasn't been opened after env.

4

The basics of environment implementation in LaTe2e are covered in How does LaTeX implement environments?. In xparse, the approach is slightly more complex as to allow #1, etc. in the end-of-environment code there is a dynamic definition. However, the performance hit is minimal. On top of LaTeX2e it's still necessary to set up \foo and \endfoo as that is what \begin and \end are looking for. However, the long-term vision is to provide a dedicated namespace for environment code, and xparse therefore includes a second 'layer' of macros for this purpose.

Joseph Wright
  • 259,911
  • 34
  • 706
  • 1,036