3

In the following MWE I would like to expand both \envnum as well as \itemnum while passing them to \cmdwithexpandedargs but only the first one got expanded. Note the different output between \wlog and \printcmd, this still intrigues me.

\documentclass{letter}

\newcounter{nenv}
\newcommand\printcmd{}

\makeatletter
\newcommand\cmdwithexpandedargs[1]{%
    \g@addto@macro\printcmd{#1 - }
}
\makeatother

\newenvironment{test}{%
    \stepcounter{nenv}%
    \let\olditem\item
    \renewcommand\item{%
        \olditem
        \xdef\envnum{\arabic{nenv}}%
        \xdef\itemnum{\alph{enumi}}%
        \wlog{\envnum.\itemnum}
        \expandafter\cmdwithexpandedargs\expandafter{\envnum\itemnum}%
    }%
    \begin{enumerate}%
}{\end{enumerate}}

\begin{document}
\begin{test}
  \item one
  \item two 
\end{test}
\begin{test}
  \item one
  \item two
  \item three
\end{test}
\printcmd
\end{document}

The \wlog output "1.a - 1.b - 2.a - 2.b - 2.c" is what I want, but it is not what \printcmd gives: "1c - 1c - 2c - 2c - 2c". I'm accepting LaTeX3 (expl3) solutions here, if required!

  • Just use \xappto\printcmd{#1 - } from etoolbox. – Manuel Jul 28 '16 at 20:11
1

You need to expand not only \envnum, but also \itemnum. That means the one line got revised to \expandafter\expandafter\expandafter\cmdwithexpandedargs\expandafter\expandafter\expandafter{\expandafter\envnum\itemnum}. After the first round of expansion, \itemnum is expanded leaving what you started with, \expandafter\cmdwithexpandedargs\expandafter{\envnum\itemnum}. This second round expands \envnum and you are good to go.

\documentclass{letter}

\newcounter{nenv}
\newcommand\printcmd{}

\makeatletter
\newcommand\cmdwithexpandedargs[1]{%
    \g@addto@macro\printcmd{#1 - }
}
\makeatother

\newenvironment{test}{%
    \stepcounter{nenv}%
    \let\olditem\item
    \renewcommand\item{%
        \olditem
        \xdef\envnum{\arabic{nenv}}%
        \xdef\itemnum{\alph{enumi}}%
        \wlog{\envnum.\itemnum}
        \expandafter\expandafter\expandafter\cmdwithexpandedargs\expandafter\expandafter\expandafter{\expandafter\envnum\itemnum}%
    }%
    \begin{enumerate}%
}{\end{enumerate}}

\begin{document}
\begin{test}
  \item one
  \item two 
\end{test}
\begin{test}
  \item one
  \item two
  \item three
\end{test}
\printcmd
\end{document}

enter image description here


AFTERNOTE

I got some magic code from Christian Tellechea:

% CODE FROM CHRISTIAN TELLECHEA
\makeatletter
\def\expandtimes(#1)#2#{\exp@ntimes@i(#1){#2}}
\def\exp@ntimes@i(#1)#2#3{%
    \ifnum#1>0 \expandafter\exec@first\else\expandafter\exec@second\fi
    {\expandafter\exp@second\expandafter{\expandafter\expandtimes\expandafter(\number%
      \numexpr#1-1)#2}}{#2}{#3}%
}
\long\def\exec@first#1#2{#1}
\long\def\exec@second#1#2{#2}
\long\def\swap@arg#1#2{#2{#1}}
\long\def\exp@second#1#2{\expandafter\swap@arg\expandafter{#2}{#1}}
\makeatother
%

that, if added to the preamble, would allow the multi-expansion syntax to be condensed to

\expandtimes(3)\cmdwithexpandedargs{\expandafter\envnum\itemnum}

to achieve the same result.

2

The difference is because you aren't expanding \itemnum when passing it to \cmdwithexpandedargs, but \wlog fully expands its argument.

You can do it more efficiently:

\documentclass{letter}

\newcounter{nenv}
\newcommand\printcmd{}

\makeatletter
\newenvironment{test}{%
    \stepcounter{nenv}%
    \let\olditem\item
    \renewcommand\item{%
        \olditem
        \xdef\printcmd{\printcmd\arabic{nenv}\alph{enumi} - }%
        \wlog{\arabic{nenv}.\alph{enumi}}%
    }%
    \begin{enumerate}%
}{\end{enumerate}}
\makeatother

\begin{document}
\begin{test}
  \item one
  \item two 
\end{test}
\begin{test}
  \item one
  \item two
  \item three
\end{test}
\printcmd
\end{document}

No need to do separate \xdef (global is actually useless and could simply be \edef).

enter image description here

In the log file you find

1.a
1.b
2.a
2.b
2.c

If you want to use \cmdwithexpandedargs, then you can do without \expandafter or fancy code.

\makeatletter
\newcommand\cmdwithexpandedargs[1]{%
    \g@addto@macro\printcmd{#1 - }
}
\makeatother

\newenvironment{test}{%
    \stepcounter{nenv}%
    \let\olditem\item
    \renewcommand\item{%
        \olditem
        \wlog{\arabic{nenv}.\alph{enumi}}
        \begingroup\edef\x{\endgroup
          \noexpand\cmdwithexpandedargs{\arabic{nenv}\alph{enumi}}%
        }\x
    }%
    \begin{enumerate}%
}{\end{enumerate}}
  • Your simplified solution works like a charm for this MWE but I need the other command (\cmdwithexpandedargs) in my full code. What I didn't understand is why \arabic and \alph didn't get expanded with \xdef. I thought there is no need to use \expandafter while using those \xdef (or \edef). But in this MWE everything works like those macros were never expanded, even with \xdef, why? – bgeneto Jul 29 '16 at 11:52
  • 1
    @bgeneto They did get expanded and their expansion assigned to \envnum and \itemnum. But you didn't expand both of these macros before passing the tokens to \g@addto@macro. I added a way with the intermediate step with \cmdwithexpandedargs. – egreg Jul 29 '16 at 12:16
  • You are right, in fact they got expanded in \xdef, but then not as argument to \cmdwithexpandedargs. Thanks for such an elegant solution, as always! – bgeneto Jul 29 '16 at 12:43

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.