# How to define a macro with parameters inside a beamer frame

To ease the typesetting of nontrivial beamer frames I often employ local helper macros. This is not too easy in beamer, as defining a macro with parameters (e.g., \def\myfmt#1{\emph{#1}}) between \begin{frame} and \end{frame} fails with:

! Illegal parameter number in definition of \beamer@doifinframe.
1
l.11 \end{frame}


The commonly mentioned workaround for this is to define the macro outside of the frame together with the latter inside a group:

\bgroup
\def\myfmt#1{\emph{#1}}
\begin{frame}[label=problem]{A frame that uses a ,,local'' macro}
\myfmt{Slide content}
\end{frame}
\egroup


This, however, does not work if one wants to use the frame with \againframe later (complete MWE):

\documentclass{beamer}
\begin{document}

\bgroup
\def\myfmt#1{\emph{#1}}
\begin{frame}[label=problem]{A frame that uses a ,,local'' macro}
\myfmt{Slide content}
\end{frame}
\egroup

\bgroup
\def\myfmt#1{\color{red} #1}
\begin{frame}{Another frame that uses a ,,local'' macro}
\myfmt{Slide content}
\end{frame}
\egroup

% fails with "Undefined control sequence \myfmt"
\againframe{problem}

\end{document}


Apparently, \againframe does insert only the content that was defined between \begin{frame} and \end{frame} - which makes sense, of course.

So how can I define "frame-local" helper macros that work with \againframe?

-
Use the fragile option or try to double the #: \begin{frame}[label=problem]{A frame that uses a ,,local'' macro} \def\myfmt##1{\emph{##1}} \myfmt{Slide content} \end{frame} . The frame environment is a pseudo-environment, i.e. actually \frame{ .. } in disguise. The argument is stored in a parameter-less macro and therefore the #1 is taken as its argument. –  Martin Scharrer Jul 4 '11 at 20:15
Supplement: You need to use four hashes, apparently the content is expanded twice. Using \def\myfmt####1{\emph{####1}} works for me in the frame, but not with \againframe. So using fragile seems to be the way to go. –  Martin Scharrer Jul 4 '11 at 20:19
@Martin: That should be an answer. –  Caramdir Jul 4 '11 at 21:28
@Martin: I had tried it with two #, but not with four, nice :-) However, fragile seems not to help wrt to \againframe; have you tested this? –  Daniel Jul 4 '11 at 21:38

The frame environment is a pseudo-environment, i.e. actually \frame{ .. } in disguise. The argument is stored in at least one parameter-less macro and therefore the #1 is taken as its argument. You can try doubling the #s as usual in such cases. In my tests I needed to double all # twice: \def\myfmt####1{\emph{####1}}. This then works in the first frame, but not in the \againframe. Apparently the content is assigned there again and causes issues.

The easiest solution would be to use the fragile option for the frame which warns beamer about such issues and make it process the frame more carefully.

\documentclass{beamer}
\begin{document}

\begin{frame}[label=noproblem,fragile]{A frame that uses a ,,local'' macro}
\def\myfmt#1{\emph{#1}}
\myfmt{Slide content}
\end{frame}

\begin{frame}[fragile]{Another frame that uses a ,,local'' macro}
\def\myfmt#1{\color{red} #1}
\myfmt{Slide content}
\end{frame}

\againframe{noproblem}

\end{document}


Also if you would hide the # from the \frame it would work, e.g. placing your definition inside another macro outside the frame and use that macro in the frame, but for doing this one would again need to define one macro outside the frame which defeats the purpose.

-
Thanks Martin, this works! As usual, I will wait a couple of days before accepting the answer. Comment: The only caveat with fragile is that it does not play together with allowframebreaks. However, a frame with local macros and frame-breaks that is used again with \againframe would be a pathological case anyway. –  Daniel Jul 5 '11 at 10:24
Very useful tip. I had the same problems with \docsvlist for sparklines inside a beamer document. Thanks. –  drstevok Apr 16 '13 at 17:19