Frame and Itemize together

I want to redefine frame as frame + itemize. I've so far tried this -

\documentclass{beamer}
\newenvironment{myframe}{\begin{frame}\begin{itemize}}{\end{itemize}\end{frame}}

\begin{document}
\begin{myframe}
\item
\end{myframe}
\end{document}


What exactly is wrong in this and then how to correctly redefine this?

The beamer environment frame collects its body using the following technique: it reads and stores tokens following \begin{frame} looking for \end{frame} without expanding them except in one case (see below), but it will accept an \end{frame} as the end of the environment body being collected only if it has seen the same number of \begin{...} as \end{...} during this collection process (it does not try to match them). This is what \beamer@begin@stack is used for in \beamer@collect@@body from beamerbaseframe.sty.

In case the stack is empty (i.e., it has seen as many \end{...} as \begin{...} after \begin{frame}) and the following \end{...} is not an \end{frame}, it expands this \end hoping this will make \end{frame} appear.1 But this only happens under the condition I gave (as many \end{...} as \begin{...} after the initial \begin{frame} must have been seen).

In your example, the \begin{itemize} pushes one b (i.e., opens one level) to the \beamer@begin@stack stack. This b is popped when \end{myframe} is read. At this point, \beamer@collect@@body knows it has seen as many \begin{...} as \end{...} after the \begin{frame}. This is true but misleading, since if \end{myframe} were expanded, it would yield two pops. So, \beamer@begin@stack thinks that the next \end{...} must provide \end{frame}, possibly after expanding the \end... token (see footnote 1). Alas, this is incorrect; the next \end{...} is \end{document}. \enddocument is thus expanded, then \beamer@collect@@body continues to look for \end{frame} but of course never finds it, reaches the end of the file, which triggers the error:

Runaway argument?
\let \AtEndDocument \@firstofone \@enddocumenthook \@checkend {docume\ETC.
! File ended while scanning use of \beamer@collect@@body.
<inserted text>
\par


So, basically, the problem is that \beamer@collect@@body can't keep a proper count of the \end{...} because your \end{myframe} hides two of these (\end{itemize}\end{frame}) and \beamer@collect@@body will not discover them via expansion of \endmyframe despite the presence of \end{myframe}, because it has seen more \begin{...} than \end{...} at the point where it sees this \end{myframe} (non-empty stack due to the \begin{itemize}).

The solutions require you not to hide \end{...} in macros that \beamer@collect@@body is not going to expand. One is using the environ package as in ferahfeza's answer, another is using \itemize and \enditemize as follows (neither of them affect the \beamer@begin@stack stack, therefore when \beamer@collect@@body sees \end{myframe}, the stack is empty, thus \endmyframe is expanded once, which makes the \end{frame} visible to the environment body scanning process):

\documentclass{beamer}

\newenvironment*{myframe}[1]
{\begin{frame}{#1}%
\begingroup\itemize}
{\enditemize\endgroup
\end{frame}}

\begin{document}

\begin{myframe}{Frame title}
\item An item
\item Another item
\end{myframe}

\end{document}


Footnote

1. More precisely, what happens is the following (in beamer 2018/12/02 v3.55). If:

• the \beamer@begin@stack stack is empty (as many \end{...} as \begin{...} have been seen after the \begin{frame} whose body is being collected) and
• the next \end{...} is not an \end{frame}—let's say it is an \end{foobar},

then \beamer@collect@@body substitutes the first-level expansion of \endfoobar\endgroup for this \end{foobar} in the collected material. This is similar to what expanding \end{foobar} would produce, though the latter would do a few more things (see source2e.pdf p. 272):

• check that the replacement text of \@currenvir is foobar (this would fail in the beamer frame body collection process we are talking about, as \@currenvir is frame);
• honor a previous \@endparenv command (used to suppress paragraph indentation at the beginning of text following some paragraph-making environments, unless said text is preceded by a blank line or by \par);
• honor a previous \ignorespacesafterend command (used to make the next \end{...} ignore the spaces that may follow it).
• Great! This doesn't require additional use of a package, so loved this one. Thank you so much! – Niranjan Aug 6 at 16:49
• Is there any way to add the argument \begin{frame}{frame-title} in this code? With the environ package @ferahfeza managed to incorporate it too, but I think it would be better to do it without the help of packages. – Niranjan Aug 7 at 5:10
• Sure, please see the last edit. If desired, one could add a star variant, optional arguments, arbitrary delimited arguments, whatever. – frougon Aug 7 at 6:56

Using package environ:

\documentclass{beamer}
\usepackage{environ}

\NewEnviron{myframe}[1][]{%
\begin{frame}{#1}
\begin{itemize}
\BODY
\end{itemize}
\end{frame}
}

\begin{document}
\begin{myframe}
\item First
\item Second
\end{myframe}
\end{document}


• Thanks, this worked. I just have one question, why those arguments are necessary? I removed them and compiled, still got the same result. Is there any special function associated with them? – Niranjan Aug 6 at 16:10
• (I mean \NewEnviron{myframe}[1][] these two arguments) – Niranjan Aug 6 at 16:11
• It is for title of frame; \begin{myframe}[Title of frame]. – ferahfeza Aug 6 at 16:13
• Oh, great. Thanks. One more doubt, what was wrong with my code? Why it did not work? – Niranjan Aug 6 at 16:15
• I am sorry but that argument is not working for the frame-title. I'm getting errors. I added something like \begin{myframe}{Niranjan} – Niranjan Aug 6 at 16:22