beamer
's frame
environment is very complicated, since it has to deal with the overlay specification - something inherent to beamer
that the end-user rarely have to worry about. That is, you set what looks like a single frame
environment, while beamer
translates it into a number of slides (possibly).
beamer
also reads the entire frame
environment in order to manage multiple instances of it and technically misses your \sld
's \end{frame}
. Other document classes have other ways of managing this, since they don't provide/lack beamer
overlay specification, and as such only processes frame
s once.
Here is a more lengthy and detailed discussion:
This procedure of taking "one thing" (a single frame
environment) and replicating it into "multiple things" (numerous slides) requires beamer
to grab the entire frame
environment before starting to process it. We can see this "frame
grabbing" when you look at certain components inside beamerbaseframe.sty
:
%
% The frame environment (a trifle ugly...)
%
% Copyright notice: the following code is adapted from code from the
% amsmath package.
\newtoks\beamer@envbody
\def\beamer@frameenv{%
\def\beamer@process@envbody{\endgroup%
\expandafter\expandafter\expandafter\beamer@framecommand\expandafter\beamer@frameoptions\expandafter{\the\beamer@envbody}}%
\global\beamer@envbody{}\def\beamer@begin@stack{b}%
\begingroup
\let\frame\beamer@collect@@body
\def\beamer@process@envbody{\frame}%
\beamer@process@envbody%
}
% Normally not executed; only in containsverbatim context:
\def\endframe{\egroup\begingroup\def\@currenvir{frame}}
\long\def\beamer@push@begins#1\begin#2{\ifx\end#2\else b\expandafter\beamer@push@begins\fi}
\long\def\beamer@collect@@body#1\end#2{%
\def\test{#1}%
\edef\beamer@begin@stack{\beamer@push@begins#1\begin\end \expandafter\@gobble\beamer@begin@stack}%
\ifx\@empty\beamer@begin@stack
\global\beamer@envbody\expandafter{\the\beamer@envbody#1}%
\def\reserved@a{#2}
\ifx\reserved@a\beamer@frametext%
\endgroup%
\let\@next=\beamer@process@envbody % A little tricky! Note the grouping
\@checkend{#2}%
\else%
% ok, just expand it, presumably it will generate the desired \end{frame}
\let\@next=\beamer@process@expander%
\fi
\else
\global\beamer@envbody\expandafter{\the\beamer@envbody#1\end{#2}}%
\let\@next=\beamer@process@envbody%
\fi
\@next
}
Note how \beamer@frameenv
- fundamentally, the start of the frame
environment, calls \beamer@process@envbody
, which expands to \frame
, which expands to \beamer@collect@@body
. Further down we see that \beamer@collect@@body
's parameter text is defined to include \end
. More specifically,
\long\def\beamer@collect@@body#1\end#2{...}
This means that the macro grabs everything from the start of the environment up until \end
into argument #1
, and the environment name as the argument to \end
in argument #2
. At the stage of grabbing these arguments (not only are the category codes fixed, but also) TeX has to see a visible \end
.
In your case, the only visible \end
is that of the "second" frame
. As such, what seems like two frame
s in your mind is considered a single frame
in TeX's mind. And, with an odd \end{frame}
(the expansion of \sld
) that doesn't have an accompanying \begin{frame}
, TeX complains.