3

I have some environments foo and bar that I would like to replace with the environments newfoo and newbar with the words "This is a modified foo/bar environment:" added before the environment. I am trying to do it in a loop, like so:

\documentclass{minimal}

\usepackage{amsthm}
\let\bar\relax

\newtheorem{foo}{Foo}
\newtheorem{bar}{Bar}
\newtheorem{newfoo}{New Foo}
\newtheorem{newbar}{New Bar}

\makeatletter
\@for\@env:=foo,bar\do{%
  \renewenvironment{\@env}{%
    This is a modified \@env environment: 
    \begin{new\@env}
  }{%
    \end{new\@env}
  }%
}
\makeatother


\begin{document}
\begin{foo}
I want this to be New Foo.
\end{foo}

\begin{bar}
I want this to be New Bar.
\end{bar}
\end{document}

However, this does not work because \begin does not want to expand the command \@env. I have unsuccessfully tried to add \expandafters there, but I did not manage to make it work. I have also attempted to circumvent it by using

\renewenvironment{\@env}{%
        This is a modified \@env environment: 
        \csname new\@env\endcsname
 }{%
        \csname endnew\@env\endcsname
 }%

but apparently this does not work either (I'm not actually sure why).

Can someone suggest a working solution?

3

You need to use the expansion of \@env, not \@env. It's easier with expl3. In the second argument of \xfor, #1 denotes the current item in the list being processed.

\documentclass{article}
\usepackage{xparse}
\usepackage{amsthm}
\let\bar\relax

\newtheorem{foo}{Foo}
\newtheorem{bar}{Bar}
\newtheorem{newfoo}{New Foo}
\newtheorem{newbar}{New Bar}

\ExplSyntaxOn
\NewDocumentCommand{\xfor}{mm}
 {
  \clist_map_inline:nn { #1 } { #2 }
 }
\ExplSyntaxOff

\xfor{foo,bar}{%
  \renewenvironment{#1}{%
    This is a modified #1 environment: 
    \begin{new#1}
  }{%
    \end{new#1}
  }%
}


\begin{document}
\begin{foo}
I want this to be New Foo.
\end{foo}

\begin{bar}
I want this to be New Bar.
\end{bar}
\end{document}

enter image description here

3

Without the use of expl3 you might use:

\documentclass{minimal}

\usepackage{amsthm}
\let\bar\relax

% not necessary because we don't use \renewenvironment but define the macros used for the environment later
%\newtheorem{foo}{Foo}
%\newtheorem{bar}{Bar}

\newtheorem{newfoo}{New Foo}
\newtheorem{newbar}{New Bar}

\makeatletter
\@for\@env:=foo,bar\do{%
    \expandafter\xdef\csname\@env\endcsname{%
        This is a modified \@env\ environment:
        \noexpand\begin{new\@env}}
    \expandafter\xdef\csname end\@env\endcsname{\noexpand\end{new\@env}}
}
\makeatother


\begin{document}
\begin{foo}
I want this to be New Foo.
\end{foo}

\begin{bar}
I want this to be New Bar.
\end{bar}
\end{document}
4
  • This might be very dangerous if the This is a modified... part contains commands. – egreg Aug 17 '17 at 9:01
  • @egreg yes, in this case one would have to insert some \noexpands. I just wanted to show a way without expl3 for academic purposes. – Skillmon Aug 17 '17 at 9:08
  • @egreg I'm curious, in what way is it dangerous? – Mereenie Aug 17 '17 at 12:36
  • 2
    @Mereenie imagine you want to use a command inside of the definition which must not be expanded there (for any reason, e.g. being defined later). You'd have to mark it with \noexpand every time you use such a macro (because of \xdef expanding every expandable macro during the definition). That's what makes it not that user friendly and prone to errors. – Skillmon Aug 17 '17 at 12:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.