[Tex/LaTex] Expanding arguments before macro call

expansionmacros

I've been banging my head against this for days. I have a macro which takes a macro name and its arguments. It then re-arranges the arguments a bit and then calls the passed macro with the re-arranged arguments and so ends like this:

#1{\arga}{\argb}{\argc}

where arga ... \argc are the processed arguments. However. I need to have \arga ... \argc fully expanded before the macro stored in #1 is called. I cannot for the life of me work this out after days of playing with \expandafter, \noexpand, etextools etc. I can't use expl3 and I'd really prefer not to use etextools but etoolbox is available. Here is a MWE:

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  #1{\arga}{\argb}{\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

This results in "\arga \argb \argc" but I want "arg1arg2arg3". \expandafter will do this in \x but not for three arguments in a row. etextools has some macros to do this but I really want to avoid it (it clashes with etoolbox in some ways and I must have etoolbox). I couldn't get the etextools macros to work even when I tried (\ExpandNextTwo etc.)

UPDATE: I realised that in my case, the args can contain robust macros like:

\documentclass{article}
\usepackage{etoolbox}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \edef\argb{\ifstrequal{#3}{arg2}{arg2}{}}%
  \def\argc{#4}%
  {\protected@edef\z{\noexpand#1{\arga}{\argb}{\argc}}\z}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

In which case (using egreg's answer as an example), it isn't fully expanded. As Joseph and egreg mention below, this isn't doable, you just have to use non-robust macros in such cases, for example. I'll let the question stand as it because it is informative.

Best Answer

The 'classical' approach is to use \expandafter

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter#1%
    \expandafter\expandafter\expandafter\expandafter\expandafter\expandafter\expandafter
      {\expandafter\expandafter\expandafter\arga\expandafter\expandafter\expandafter}%
        \expandafter\expandafter\expandafter{\expandafter\argb\expandafter}\expandafter
          {\argc}}

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

where we need so many of them to expand arg3 then arg2 and finally arg1. (This is what is effectively wrapped up in expl3's \exp_args:Nooo).

The rule of the number of \expandafters we need is 2n – 1, where n is how many tokens we want to expand. So for one token somewhere ahead, we need just one \expandafter in each place to be 'skipped', to expand two tokens (second one then the first one) we need three \expandafters, for three tokens (as in the current case) we need seven \expandafters, and so one. This is easiest to see if you write/print out a short second and cross off the commands as TeX would read them: you'll find everything works out.

With e-TeX available, we can use an \edef and \unexpanded:

\documentclass{article}
\begin{document}

\def\x#1#2#3#4{%
  \def\arga{#2}%
  \def\argb{#3}%
  \def\argc{#4}%
  \begingroup
    \edef\x{%
      \endgroup
      \noexpand#1
        {\unexpanded\expandafter{\arga}}%
        {\unexpanded\expandafter{\argb}}%
        {\unexpanded\expandafter{\argc}}%
    }%
  \x
}    

\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

(You can do the same without e-TeX using a series of toks, but that gets a bit confusing so I'd not normally do it.)


The question says no expl3, but for contrast the approach using a minimium of the functions it provides would read

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\def\x#1#2#3#4{
  \def\arga{#2}
  \def\argb{#3}
  \def\argc{#4}
  \exp_args:Nooo#1\arga\argb\argc
}    
\ExplSyntaxOff
\def\y#1#2#3{\detokenize{#1#2#3}}

\x\y{arg1}{arg2}{arg3}

\end{document}

which is I hope a lot more readable. (I'd probably want to use \exp_args:NVVV as we are using 'value stored in a variable', but that function is not pre-defined so I've avoided it here.)