# How to define a command that takes more than 9 arguments

I have a mathematical transformation that takes 16 parameters (grouped into 3+8+5) and would like to make a latex command for it, so that I can easily change the notation for it if the need arises.

As far as I know, both \def and \newcommand take a maximum of 9 arguments, is there any (recommended) way to extend this?

• Perhaps you might show us the detail of what is wanted. This sounds like a question where the best answer will be to think carefully about the input you really require. – Joseph Wright Aug 21 '10 at 6:43
• I edited the question to make it clear the parameters are not programmatic, but rather, an unavoidable part of the the maths that I'm using. – Simon Aug 21 '10 at 7:02
• I wonder if there's a magic solution involving Currying. – Seamus Feb 21 '13 at 16:19

You are going to have to parse the arguments some at a time and store them into temporary registers or macros. For example

\newcommand\foo[9]{%
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\def\tempi{#9}%
\foocontinued
}
\newcommand\foocontinued[7]{%
% Do whatever you want with your 9+7 arguments here.
}

• Thanks TH - that's the same solution as supplied in the "black TeX magic" link provided by mindcorrosive. I think that I'll use the xargs package, since it will make my code clearer and I like the simple default arguments. – Simon Aug 21 '10 at 6:55
• Can you give an example of how to declare and access/use the variables? – 7heViking Oct 15 '15 at 15:10
• I ask the same question as @FireFly3000 . I did as you said above and called the two functions as follows: \pointscolors{100}{red}; \myarc{0}{0}{0}{0}{3}{2.645751311064591}{0}{-3}{2.645751311064591}; (sorry, I do not know how to format this), with 2 arguments and the next with 9 arguments. then I get this error: Argument of \myarc has an extra }. <inserted text> \par l.90 ...myarc{0}{0}{0}{0}{3}{2.645751311064591}{0} {-3}{2.645751311064591}; ? – Herman Jaramillo Nov 2 '15 at 23:01
• I removed the "\foocontinued" from the first block (named "\foo") and my error disappeared. I think that line is in error because is called without parameters. – Herman Jaramillo Nov 2 '15 at 23:32
• Within the definition-text of \foocontinued you can use the macros \tempa..\tempi and the arguments #1..#7, so within the definition-text of \foocontinued the first nine arguments are addressable via macro-calls and the following seven nine arguments are addressable via #<digit>-syntax. – Ulrich Diez Oct 21 '18 at 17:47

There's the xargs package, and there's also some black TeX magic. As for myself, being conditioned in Python, I prefer the key-value parameter syntax provided by keyval/xkeyval packages.

On an unrelated note, if I find myself needing more than 9 parameters, that usually means that my macro/def/code organization is not very good, and I'd try to improve that first. But of course, there are legitimate situations where 9 parameters are perfectly okay --- especially if you try to build a definition with a lot of knobs and tweaks.

• Thanks, I don't know how my googling did not turn up the first option you gave. The 16 parameters define a nonlinear transformation - they're not options in the macro. – Simon Aug 21 '10 at 6:51
• Actually, xargs does not allow more than 9 arguments - it only gives a neat interface for optional arguments. I'll have to use the TeX hack. – Simon Aug 21 '10 at 7:10
• That's correct. Until you clarified what you need so much parameters for, I assumed it's for a macro, and you'd use the keyval interface. But of course in that case it's better with plain TeX. – Martin Tapankov Aug 21 '10 at 7:15
• Actually you made me reconsider if I needed all those arguments and I ended up with 6 arguments in stead of 10 :) – 7heViking Oct 15 '15 at 16:05

The listofitems package used here is preferable to my original answers below, because \readlist does not expand the argument when capturing it, nor does it rely on inconvenient roman-numeral syntax.

\documentclass{article}
\usepackage{listofitems}
\begin{document}
\setsepchar{ }
\readlist\arg{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \arglen{} arguments.  The thirteenth is \arg[13]
\end{document}


In a response to How to use variables inside a command when generating a table? I mention how the stringstrings package has a \getargs command that will parse large numbers of arguments that are passed within a single { }. To recap that reply,

\documentclass{article}
\usepackage{stringstrings}
\begin{document}
\getargs{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \narg~arguments.  The thirteenth is \argxiii
\end{document}


The result to this example is:

There are 13 arguments. The thirteenth is FinalArgument

EDIT: A much more efficient version of \getargs is available in the readarray package and called \getargsC (in deference to David Carlisle's help). Thus, the same task can be accomplished more quickly with

\documentclass{article}
\begin{document}
\getargsC{1 2 3 4 5 6 7 8 9 10 11 12 FinalArgument}
There are \narg~arguments.  The thirteenth is \argxiii
\end{document}

• Could you please edit your answer to show how these techniques can be used to define a command taking several arguments? – Psychonaut Feb 9 '17 at 14:03
• @Psychonaut when you say several arguments, do you mean several arguments within a single set of braces? For example, the listofitems answer at the end of this answer: tex.stackexchange.com/questions/348366/… – Steven B. Segletes Feb 9 '17 at 14:44
• It's also worth mentioning that the stringstrings package has some unwanted side effects due to definitions of \t et al, that are commonly used by latex users as shortcuts. BTW, the readarray package doesn't do that and seems a better alternative. – Geoff Pointer Aug 11 '17 at 1:11

Since it's a different technique, I also present the following: local macro definitions.

\documentclass{article}

\def\NineteenArgs#1#2#3#4#5#6#7#8#9{%
\def\ArgsTenAndFurther##1##2##3##4##5##6##7##8##9{%
\def\ArgNineteen####1{%
####1##9##8##7##6##5##4##3##2##1#9#8#7#6#5#4#3#2#1%
}%
\ArgNineteen%
}%
\ArgsTenAndFurther%
}

\begin{document}
%1234567890123456789
\NineteenArgs abcdefghijklmnopqrs
\end{document}

• This is beautiful, in a horrifying sort of way. I wanted \matr 1110 1110 1110 0000, and \newcommand{\matr}[9]{\def\matrMore##1##2##3##4##5##6##7{\begin{bmatrix}#1&#2&#3&#4\\#5&#6&#7&#8\\#9&##1&##2&##3\\##4&##5&##6&##7\end{bmatrix}}\matrMore} did the trick perfectly! – Radon Rosborough Mar 26 '17 at 2:03
• Glad it helped. I trust you like the transparency of the argument naming scheme:-) – user10274 Mar 26 '17 at 15:25

First, we define the command \foo. It contains a nested command definition for parameters extension. Note it is declared using \neworrenewcommand, which defines a command if not defined, or redefine it if it is already defined.*

Parameters with one dash are bound to the first command, while parameters with two dashes are bound to the second command. MWE:

\documentclass{article}

% Provide a way to declare and renew a command in one command

\newcommand{\foo}[9]{
\neworrenewcommand{\ffoo}[1]{
#1 #2 #3 #4 #5 #6 #7 #8 #9 ##1
}
\ffoo
}

\begin{document}
\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}

\foo{a}{b}{c}{d}{e}{f}{g}{h}{i}{j}
\end{document}


Preview of the result:

*This is necessary, since the calling \foo multiple times redefines the nested command. The \neworrenewcommand trick is further explained here.

• Welcome to TeX.SX! This is more or less the same as the answer up above: tex.stackexchange.com/a/165324/134574 (using \newcommand instead of \def). – Phelype Oleinik Sep 25 '19 at 19:04
• Hey! Thank you! Yes, I was wondering if that was possible with \newcommand as well and it was. I felt in the mood for documenting it here. :) – Jämes Sep 25 '19 at 19:14
• This gives an error if one wants to use the command consecutively, e.g two times. Error message: Command *** already defined. For a working solution look at diligar's answer from above and at Ulrich Diez's comment on it. tex.stackexchange.com/a/418343/76400 – Philipp H Apr 13 '20 at 10:11
• @PhilippH This is because the subcommand (ffoo) is renewed when called multiple times. I changed its definition using providecommand, so it works with multiple invocations. – Jämes Jun 4 '20 at 13:54
• @Teepeemm \providecommand defines a new command if it isn't already defined. Therefore, the first time the nested command is created and subsequent calls will not redefine it. – Jämes Jun 8 '20 at 8:01

This assumes no argument of a weird command contains a weird command. Here for “weird command” I mean one defined with the proposed \NewWeirdCommand below.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\NewWeirdCommand}{mmm}
{% #1 = command to define, #2 = number of arguments, #3 = replacement text
\cs_new:Npn #1
{
\tl_set:Nn \l__simon_parse_args_tl { #3 }
\__simon_parse_args:n { #2 }
}
}
\NewDocumentCommand{\Arg}{m}
{
\seq_item:Nn \l__simon_parse_args_seq { #1 }
}

\tl_new:N \l__simon_parse_args_tl
\seq_new:N \l__simon_parse_args_seq
\int_new:N \l__simon_parse_args_int

\cs_new_protected:Nn \__simon_parse_args:n
{
\seq_clear:N \l__simon_parse_args_seq
\int_zero:N \l__simon_parse_args_int
\__simon_parse_arg:n { #1 }
}
\cs_new_protected:Nn \__simon_parse_arg:n
{
\int_incr:N \l__simon_parse_args_int
\int_compare:nNnTF { \l__simon_parse_args_int } > { #1 }
{
\tl_use:N \l__simon_parse_args_tl
}
{
\__simon_parse_arg_aux:nn { #1 }
}
}
\cs_new_protected:Nn \__simon_parse_arg_aux:nn
{
\seq_put_right:Nn \l__simon_parse_args_seq { #2 }
\__simon_parse_arg:n { #1 }
}
\ExplSyntaxOff

\begin{document}

\NewWeirdCommand{\foo}{4}{\Arg{1}-\Arg{2}-\Arg{3}-\Arg{4}END}
\NewWeirdCommand{\baz}{16}{%
\Arg{16}-%
\Arg{15}-%
\Arg{14}-%
\Arg{13}-%
\Arg{12}-%
\Arg{11}-%
\Arg{10}-%
\Arg{9}-%
\Arg{8}-%
\Arg{7}-%
\Arg{6}-%
\Arg{5}-%
\Arg{4}-%
\Arg{3}-%
\Arg{2}-%
\Arg{1}-%
END%
}

\foo{a}{b}{c}{d}XXXX

\baz{a1}{b1}{c1}{d1}{a2}{b2}{c2}{d2}{a3}{b3}{c3}{d3}{a4}{b4}{c4}{d4}XXXX

\end{document}


In the replacement text, \Arg{<number>} denotes the corresponding collected argument.

No check is done, so if you define a weird command to have 15 arguments, \Arg{16} in the replacement text will output nothing.

If you are willing to use a slightly different syntax, with all arguments in an additional pair of braces, it's simpler:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\NewWeirdCommand}{mm}
{% #1 = command to define, #2 = replacement text
\cs_new:Npn #1 ##1
{
\tl_set:Nn \l__simon_args_tl { ##1 }
#2
}
}
\NewDocumentCommand{\Arg}{m}
{
\tl_item:Nn \l__simon_args_tl { #1 }
}

\tl_new:N \l__simon_parse_args_tl
\ExplSyntaxOff

\begin{document}

\NewWeirdCommand{\foo}{\Arg{1}-\Arg{2}-\Arg{3}-\Arg{4}END}
\NewWeirdCommand{\baz}{%
\Arg{16}-%
\Arg{15}-%
\Arg{14}-%
\Arg{13}-%
\Arg{12}-%
\Arg{11}-%
\Arg{10}-%
\Arg{9}-%
\Arg{8}-%
\Arg{7}-%
\Arg{6}-%
\Arg{5}-%
\Arg{4}-%
\Arg{3}-%
\Arg{2}-%
\Arg{1}-%
END%
}

\foo{{a}{b}{c}{d}}XXXX

\baz{{a1}{b1}{c1}{d1}{a2}{b2}{c2}{d2}{a3}{b3}{c3}{d3}{a4}{b4}{c4}{d4}}XXXX

\end{document}

• Hehe, the weird command. I like it. :P – manooooh Oct 22 '18 at 0:19

I can offer a macro \KeepKthOfLArguments which picks the K-th undelimited argument of a sequence of L undelimited arguments.

When doing macro-programming, you can pass the sequence of L undelimited arguments via a single undelimited macro argument.

I don't recommend using this for macros at user-level.

At user-level I recommend interfaces with keyval-syntax.

But sometimes I use such things with macros that both generate and process large lists of undelimited arguments automatically without the need of the user passing/typing these arguments.

\documentclass{article}

\makeatletter
%% Code for \KeepKthOfLArguments:
%%=============================================================================
%% Paraphernalia:
%% \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond, \UD@CheckWhetherNull
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%=============================================================================
%% Keep only the K-th of L consecutive undelimited arguments.
%%   ( IF K < 1 OR K > L just remove L consecutive undelimited arguments. )
%%=============================================================================
%% \KeepKthOfLArguments{<integer number K>}%
%%                     {<integer number L>}%
%%                     <sequence of L consecutive undelimited arguments>
%%
%% If L < 1 yields nothing.
%% Else:
%%   If K >= 1 and K < L  yields:
%%     <K-th undelimited argument from <sequence of L consecutive undelimited
%%      arguments>>
%%   If K < 1 or K > L
%%     (-> there is no K-th argument in the
%%         <sequence of L consecutive undelimited arguments> )
%%   yields nothing  but removal of <sequence of L consecutive
%%          undelimited arguments>
\newcommand\KeepKthOfLArguments[2]{%
% #1: <integer number K>
% #2: <integer number L>
\romannumeral0%
\expandafter\UD@KeepKthOfLArgumentsKSmallerOneFork
\expandafter{\romannumeral\number\number#1 000\expandafter}%
\expandafter{\romannumeral\number\number#2 000}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsKSmallerOneFork[2]{%
% #1: <K letters m>
% #2: <L letters m >
\UD@CheckWhetherNull{#1}{% K is smaller than one:
\UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }{}%
}{% K is not smaller than one:
\expandafter\UD@PassFirstToSecond
\expandafter{%
\UD@firstoftwo{}#1%
}{%
\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop{#1}{#2}%
}{#2}%
}%
}%
%%-----------------------------------------------------------------------------
\newcommand\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop[4]{%
% #1: <K letters m>
% #2: <L letters m>
% (For detecting whether K>L or K<=L, during the loop letters m will
%  be removed both from #1 and #2 until at least one of these arguments
%  is empty.
%  When the loop terminates due to #1 being empty, this implies
%  K<=L #1. In this case #2 will hold an amount of letters m
%  corresponding to the the difference L-K.
%  When the loop terminates due to #2 being empty and #1 not
%  being empty, this implies K>L.
% )
% #3: <K-1 letters m>
% #4: <L letters m>
% (#3 and #4 will be left untouched during the loop so they can be
%  used for performing the appropriate action when the loop
%  terminates as it is known whether K>L.)
\UD@CheckWhetherNull{#1}{% We have K<=L:
\UD@KeepKthOfLArgumentsRemoveNArguments{%
#3%
}{%
\UD@KeepKthOfLArgumentsRemoveNArguments{#2}{ }%
}{}%
}{%
\UD@CheckWhetherNull{#2}{% We have K>L:
\UD@KeepKthOfLArgumentsRemoveNArguments{#4}{ }{}%
}{% We don't know yet whether K<=L or K>L, thus remove letters m and
% do another iteration:
\expandafter\UD@PassFirstToSecond
\expandafter{%
\UD@firstoftwo{}#2%
}{%
\expandafter\UD@KeepKthOfLArgumentsEvaluateLMinusKDifferenceLoop
\expandafter{%
\UD@firstoftwo{}#1%
}%
}{#3}{#4}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% \UD@KeepKthOfLArgumentsRemoveNArguments{<N letters m>}%
%%                                        {<argument 1>}%
%%                                        {<argument 2>}%
%%                                        <sequence of consecutive
%%                                         undelimited arguments>
%%.............................................................................
%% Removes the first N undelimited arguments from the <sequence of
%% consecutive undelimited arguments>, then inserts
%% <argument 1><argument 2>
%%
%% On the one hand when providing <argument 2> empty, you can use
%% <argument 1> for nesting calls to \UD@KeepKthOfLArgumentsRemoveNArguments.
%% On the other hand you can provide a <space token> for stopping
%% \romannumeral-expansion as  <argument 1> and have the
%% macro grab the <K-th undelimited argument> from the <sequence of L
%% consecutive undelimited arguments> as <argument 2>.
%%
\newcommand\UD@KeepKthOfLArgumentsRemoveNArguments[3]{%
%% #1: <N letters m>
%% #2: <Argument 1>
%% #3: <Argument 2>
\UD@CheckWhetherNull{#1}{#2#3}{%
\UD@firstoftwo{%
\expandafter\UD@KeepKthOfLArgumentsRemoveNArguments
\expandafter{%
\UD@firstoftwo{}#1%
}{#2}{#3}%
}%
}%
}%
%%-----------------------------------------------------------------------------
%% End of code for \KeepKthOfLArguments.
\makeatother

\newcommand\MacroWithThirtyNestedParameters[1]{%
This is paramter 1: \textbf{\KeepKthOfLArguments{1}{30}#1}\\
This is paramter 2: \textbf{\KeepKthOfLArguments{2}{30}#1}\\
This is paramter 3: \textbf{\KeepKthOfLArguments{3}{30}#1}\\
This is paramter 4: \textbf{\KeepKthOfLArguments{4}{30}#1}\\
This is paramter 5: \textbf{\KeepKthOfLArguments{5}{30}#1}\\
This is paramter 6: \textbf{\KeepKthOfLArguments{6}{30}#1}\\
This is paramter 7: \textbf{\KeepKthOfLArguments{7}{30}#1}\\
This is paramter 8: \textbf{\KeepKthOfLArguments{8}{30}#1}\\
This is paramter 9: \textbf{\KeepKthOfLArguments{9}{30}#1}\\
This is paramter 10: \textbf{\KeepKthOfLArguments{10}{30}#1}\\
This is paramter 11: \textbf{\KeepKthOfLArguments{11}{30}#1}\\
This is paramter 12: \textbf{\KeepKthOfLArguments{12}{30}#1}\\
This is paramter 13: \textbf{\KeepKthOfLArguments{13}{30}#1}\\
This is paramter 14: \textbf{\KeepKthOfLArguments{14}{30}#1}\\
This is paramter 15: \textbf{\KeepKthOfLArguments{15}{30}#1}\\
This is paramter 16: \textbf{\KeepKthOfLArguments{16}{30}#1}\\
This is paramter 17: \textbf{\KeepKthOfLArguments{17}{30}#1}\\
This is paramter 18: \textbf{\KeepKthOfLArguments{18}{30}#1}\\
This is paramter 19: \textbf{\KeepKthOfLArguments{19}{30}#1}\\
This is paramter 20: \textbf{\KeepKthOfLArguments{20}{30}#1}\\
This is paramter 21: \textbf{\KeepKthOfLArguments{21}{30}#1}\\
This is paramter 22: \textbf{\KeepKthOfLArguments{22}{30}#1}\\
This is paramter 23: \textbf{\KeepKthOfLArguments{23}{30}#1}\\
This is paramter 24: \textbf{\KeepKthOfLArguments{24}{30}#1}\\
This is paramter 25: \textbf{\KeepKthOfLArguments{25}{30}#1}\\
This is paramter 26: \textbf{\KeepKthOfLArguments{26}{30}#1}\\
This is paramter 27: \textbf{\KeepKthOfLArguments{27}{30}#1}\\
This is paramter 28: \textbf{\KeepKthOfLArguments{28}{30}#1}\\
This is paramter 29: \textbf{\KeepKthOfLArguments{29}{30}#1}\\
This is paramter 30: \textbf{\KeepKthOfLArguments{30}{30}#1}%
}%

\begin{document}

\noindent
\MacroWithThirtyNestedParameters{%
{Word 1}%
{Word 2}%
{Word 3}%
{Word 4}%
{Word 5}%
{Word 6}%
{Word 7}%
{Word 8}%
{Word 9}%
{Word 10}%
{Word 11}%
{Word 12}%
{Word 13}%
{Word 14}%
{Word 15}%
{Word 16}%
{Word 17}%
{Word 18}%
{Word 19}%
{Word 20}%
{Word 21}%
{Word 22}%
{Word 23}%
{Word 24}%
{Word 25}%
{Word 26}%
{Word 27}%
{Word 28}%
{Word 29}%
{Word 30}%
}%

\vfill

\noindent\verb|\KeepKthOfLArguments| does deliver the result after two
expansion-steps:

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\KeepKthOfLArguments{3}{11}{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}%
}%

\noindent\texttt{\string\test: \meaning\test}%

\vfill\vfill

\end{document}


In case you don't like to specify the amount of undelimited arguments but only which one to pick, if present, I can offer a macro \ExtractKthArg.

When doing macro-programming, you can pass an arbitrary sequence of undelimited arguments via nesting that sequence into a single undelimited macro argument and apply \ExtractKthArg on that single argument for extracting a specific element from the sequence.

\documentclass{article}

\pagestyle{empty}

\makeatletter
%% Code for \ExtractKthArg
%%=============================================================================
%% Paraphernalia:
%%    \UD@firstoftwo, \UD@secondoftwo, \UD@PassFirstToSecond,
%%    \UD@CheckWhetherNull,
%%=============================================================================
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
\newcommand\UD@PassFirstToSecond[2]{#2{#1}}%
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%=============================================================================
%% Extract K-th inner undelimited argument:
%%
%% \ExtractKthArg{<integer K>}{<list of undelimited arguments>}
%%
%% In case there is no K-th argument in <list of undelimited arguments> :
%%   Does not deliver any token.
%% In case there is a K-th argument in <list of undelimited arguments> :
%%   Does deliver that K-th argument with one level of braces removed.
%%
%% Examples:
%%
%%   \ExtractKthArg{0}{ABCDE} yields: <nothing>
%%
%%   \ExtractKthArg{3}{ABCDE} yields:  C
%%
%%   \ExtractKthArg{3}{AB{CD}E} yields:  CD
%%
%%   \ExtractKthArg{4}{{001}{002}{003}{004}{005}} yields: 004
%%
%%   \ExtractKthArg{6}{{001}{002}{003}} yields: <nothing>
%%
%%=============================================================================
\newcommand\ExtractKthArg[1]{%
\romannumeral0%
% #1: <integer number K>
\expandafter\UD@ExtractKthArgCheck
\expandafter{\romannumeral\number\number#1 000}%
}%
\newcommand\UD@ExtractKthArgCheck[2]{%
\UD@CheckWhetherNull{#1}{ }{%
\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}{#2}%
}%
}%
\newcommand\UD@ExtractKthArgLoop[2]{%
\UD@CheckWhetherNull{#2}{ }{%
\UD@CheckWhetherNull{#1}{%
\UD@ExtractFirstArgLoop{#2\UD@SelDOm}%
}{%
\expandafter\UD@PassFirstToSecond\expandafter{\UD@firstoftwo{}#2}%
{\expandafter\UD@ExtractKthArgLoop\expandafter{\UD@firstoftwo{}#1}}%
}%
}%
}%
\newcommand\UD@RemoveTillUD@SelDOm{}%
\long\def\UD@RemoveTillUD@SelDOm#1#2\UD@SelDOm{{#1}}%
\newcommand\UD@ExtractFirstArgLoop[1]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@firstoftwo{}#1}%
{\UD@firstoftwo{\expandafter}{} \UD@secondoftwo{}#1}%
{\expandafter\UD@ExtractFirstArgLoop\expandafter{\UD@RemoveTillUD@SelDOm#1}}%
}%
%% End of code for \ExtractKthArg.
\makeatother

\newcommand\MacroWithThirtyNestedParameters[1]{%
This is paramter 1: \textbf{\ExtractKthArg{1}{#1}}\\
This is paramter 2: \textbf{\ExtractKthArg{2}{#1}}\\
This is paramter 3: \textbf{\ExtractKthArg{3}{#1}}\\
This is paramter 4: \textbf{\ExtractKthArg{4}{#1}}\\
This is paramter 5: \textbf{\ExtractKthArg{5}{#1}}\\
This is paramter 6: \textbf{\ExtractKthArg{6}{#1}}\\
This is paramter 7: \textbf{\ExtractKthArg{7}{#1}}\\
This is paramter 8: \textbf{\ExtractKthArg{8}{#1}}\\
This is paramter 9: \textbf{\ExtractKthArg{9}{#1}}\\
This is paramter 10: \textbf{\ExtractKthArg{10}{#1}}\\
This is paramter 11: \textbf{\ExtractKthArg{11}{#1}}\\
This is paramter 12: \textbf{\ExtractKthArg{12}{#1}}\\
This is paramter 13: \textbf{\ExtractKthArg{13}{#1}}\\
This is paramter 14: \textbf{\ExtractKthArg{14}{#1}}\\
This is paramter 15: \textbf{\ExtractKthArg{15}{#1}}\\
This is paramter 16: \textbf{\ExtractKthArg{16}{#1}}\\
This is paramter 17: \textbf{\ExtractKthArg{17}{#1}}\\
This is paramter 18: \textbf{\ExtractKthArg{18}{#1}}\\
This is paramter 19: \textbf{\ExtractKthArg{19}{#1}}\\
This is paramter 20: \textbf{\ExtractKthArg{20}{#1}}\\
This is paramter 21: \textbf{\ExtractKthArg{21}{#1}}\\
This is paramter 22: \textbf{\ExtractKthArg{22}{#1}}\\
This is paramter 23: \textbf{\ExtractKthArg{23}{#1}}\\
This is paramter 24: \textbf{\ExtractKthArg{24}{#1}}\\
This is paramter 25: \textbf{\ExtractKthArg{25}{#1}}\\
This is paramter 26: \textbf{\ExtractKthArg{26}{#1}}\\
This is paramter 27: \textbf{\ExtractKthArg{27}{#1}}\\
This is paramter 28: \textbf{\ExtractKthArg{28}{#1}}\\
This is paramter 29: \textbf{\ExtractKthArg{29}{#1}}\\
This is paramter 30: \textbf{\ExtractKthArg{30}{#1}}%
}%

\begin{document}

\vspace*{-1in}\enlargethispage{1in}

\noindent\verb|\ExtractKthArg{-1}{ABCDE}|: \ExtractKthArg{-1}{ABCDE}\\
\verb|\ExtractKthArg{0}{ABCDE}|: \ExtractKthArg{0}{ABCDE}\\
\verb|\ExtractKthArg{1}{ABCDE}|: \ExtractKthArg{1}{ABCDE}\\
\verb|\ExtractKthArg{2}{ABCDE}|: \ExtractKthArg{2}{ABCDE}\\
\verb|\ExtractKthArg{3}{ABCDE}|: \ExtractKthArg{3}{ABCDE}\\
\verb|\ExtractKthArg{4}{ABCDE}|: \ExtractKthArg{4}{ABCDE}\\
\verb|\ExtractKthArg{5}{ABCDE}|: \ExtractKthArg{5}{ABCDE}\\
\verb|\ExtractKthArg{6}{ABCDE}|: \ExtractKthArg{6}{ABCDE}

\vfill

\noindent
\MacroWithThirtyNestedParameters{%
{Word 1}%
{Word 2}%
{Word 3}%
{Word 4}%
{Word 5}%
{Word 6}%
{Word 7}%
{Word 8}%
{Word 9}%
{Word 10}%
{Word 11}%
{Word 12}%
{Word 13}%
{Word 14}%
{Word 15}%
{Word 16}%
{Word 17}%
{Word 18}%
{Word 19}%
{Word 20}%
{Word 21}%
{Word 22}%
{Word 23}%
{Word 24}%
{Word 25}%
{Word 26}%
{Word 27}%
{Word 28}%
{Word 29}%
{Word 30}%
}%

\vfill

\noindent\verb|\ExtractKthArg| does deliver the result after two
expansion-steps:

\begin{verbatim}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\ExtractKthArg{3}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%
\end{verbatim}

\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\test
\expandafter\expandafter\expandafter{%
\ExtractKthArg{3}{{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}}%
}%

\noindent\texttt{\string\test: \meaning\test}%

\vfill\vfill

\end{document}


With both examples everything works by means of expansion only. No temporary macros get defined from arguments. This implies that the arguments themselves can contain hashes. E.g., things like #1 don't yield error-messages as would be the case when "naively" defining temporary macros in terms of \def from such arguments. This also implies that arguments can contain consecutive hashes, e.g., ##, without them being reduced to a single hash # as would be the case at the time of expanding temporary macros defined from such arguments.

I show something similar as ergreg's solution, but without usage of any special macro language. Only pure TeX language is used.

\newcount\argnum
\def\argsdef#1#2{\def#1{\argnum=1\def\useargs{#2}\inargs}}
\def\inargs{\futurelet\next\inargsA}
\def\inargsA{\ifx\next\bgroup \expandafter\inargsB \else \expandafter\useargs \fi}
\def\inargsB#1{\expandafter\def\csname Arg:\the\argnum\endcsname{#1}%
\inargs}
\def\arg#1{\csname Arg:#1\endcsname}

\argsdef\a{\arg{1}:\arg{3}:\arg{5}::\arg{11}:\arg{13}}
\argsdef\b{\arg{6}-\arg{5}-\arg{4}-\arg{3}-\arg{2}-\arg{1}}

\a{A}{B}{C}{D}{E}{F}{G}{H}{I}{J}{K}{L}{M}

\b{a}{b}{c}{d}{e}{f}


Better way should be:

\newcommand\foo[9]{%
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\foocontinued%#9 <- remove it
}

\newcommand\foocontinued[7]{%
% Do whatever you want with your 8+7 arguments here.
}


Then later

\foo{1}{2}{3}{4}{5}{6}{7}{8}{9}{10}{11}{12}{13}{14}{15}


e.g. NO doble bracket there.

But this solution is not elegant at all, but working.

• What does this add to an already existing answer? – egreg Jun 13 '20 at 21:18
• Defining macros \tempa...\temph from the first eight arguments implies the need of expanding these macros. During expansion two consecutive hashes from a macro's definition text will collapse into one hash. In order to avoid/compensate this you can use \edef\tempa{\unexpanded{#1}}% instead of \def\tempa{#1}%, etc. – Ulrich Diez Jul 30 '20 at 23:03

I was having the same error as @Herman-Jaramillo, so here is my correction of @TH's answer:

\newcommand\foo[9]{%
\def\tempa{#1}%
\def\tempb{#2}%
\def\tempc{#3}%
\def\tempd{#4}%
\def\tempe{#5}%
\def\tempf{#6}%
\def\tempg{#7}%
\def\temph{#8}%
\foocontinued#9
}
\newcommand\foocontinued[7]{%
% Do whatever you want with your 8+7 arguments here.
}


Then later:

\foo{1}{2}{3}{4}{5}{6}{7}{8}{{9}{10}{11}{12}{13}{14}{15}}


Notice that 9 through 15 are themselves in brackets. This solution is not perfect, since you cannot use 15 sets of brackets next to each other as cleanly as one might desire, but it worked for me.

• Defining macros \tempa...\temph from the first eight arguments implies the need of expanding these macros. During expansion two consecutive hashes from a macro's definition text will collapse into one hash. In order to avoid/compensate this you can use \edef\tempa{\unexpanded{#1}}% instead of \def\tempa{#1}%, etc. – Ulrich Diez Jul 30 '20 at 23:26