The reason the end code can't make references to the arguments passed to the start code is that they are expanded separately. That is, if you have an environment myenv
taking one argument and you write
\begin{myenv}{myarg}
some text...
\end{myenv}
then LaTeX expands \begin{myenv}
, passing it the single argument myarg
, and pastes the result in front of "some text...". The document then proceeds as it will, with other environments possibly opening and closing (perhaps even other instances of myenv
) before \end{myenv}
is finally reached. When that happens, it gets expanded, but there is no way of knowing anymore what the argument to the original \begin{myenv}
was. Thus, there is no way of passing it to the end code unless you chose to save its value.
It's worth examining why this is confusing compared to \newcommand
. Both appear to work in the same way:
\newcommand{\mymacro}[1]{macro code with #1}
\newenvironment{myenv}[1]{start code with #1}{end code}
The difference is that a macro is a single thing, which is reflected in the notation: you write \mymacro
with a backslash but myenv
without, perhaps signifying that it is a higher-level abstraction. Indeed, \newenvironment
creates a pair of macros \myenv
and \endmyenv
which function as described above.
The setup is designed to create the appearance of "blocking off" the document into chunks contained in various environments, but in fact, the unity of each environment is a bit illusory. LaTeX keeps track of the name of the environment it most recently entered, but at no time (barring clever tricks) does it ever "see" the entire environment at once, either forward (when starting) nor backwards (when ending).
xparse
package, you have\NewDocumentEnvironment
where it's possible to refer to the arguments also in the closing code.\NewDocumentEnvironment
cause the start code to create a unique macro name, known to the end code, storing the arguments? Or does it look ahead? Some kind of call stack, perhaps?\envargs
which gets filled each time an environment is called with arguments? So then TeX itself takes care of the "call stack" by saving and restoring its value when passing through nested environments.xparse
as a good solution.