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?

2 Answers 2

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
    Commented Aug 17, 2017 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
    Commented Aug 17, 2017 at 9:08
  • @egreg I'm curious, in what way is it dangerous?
    – Mmmm
    Commented Aug 17, 2017 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
    Commented Aug 17, 2017 at 12:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .