# xparse creates infinite loop

this MWE creates on my machine a infinite loop. Can someone explain to me why?

\documentclass{article}

\usepackage{booktabs,xparse}
\NewDocumentCommand\hlineX{ m O{0pt} O{#2} }{%
\specialrule{#1}{#2}{#3}%
}%

\begin{document}
\begin{tabular}{|l|l|l|}
\hline
1    & 2    & 3 \\
\hlineX{1pt}
4    & 5    & 6 \\
\hline
\end{tabular}
\end{document}


In my main document I created I get different errors: "Misplaced \noalign. [ E]" "Missing } inserted. [ E]" and so on. It's very like the MWE but with more packages loaded.

When I use the \specialrule command without xparse it works just fine..

• you can not hide a tabular rule inside a robust command with optional arguments. There is then code before the \noalign which is not allowed there. Jan 4 at 20:07

It seems the \hlineX should be expandable, since a simplified example will cause the same problem.

\documentclass{article}

\usepackage{booktabs,xparse}
\protected\def\xline{\specialrule{1pt}{0pt}{0pt}}

\begin{document}
\begin{tabular}{|l|l|l|}
\hline
1    & 2    & 3 \\
\xline
4    & 5    & 6 \\
\hline
\end{tabular}
\end{document}


The expandable variant of \NewDocumentCommand is \NewExpandableDocumentCommand, and since it defines expandable new command, the argument specification should not end with optional arguments. Therefore we have the following working example, with the syntax of \hlinex modified:

\documentclass{article}

\usepackage{booktabs,xparse}
\NewExpandableDocumentCommand\hlineX{ O{0pt} O{#1} m }{%
\specialrule{#3}{#1}{#3}%
}

\begin{document}
\begin{tabular}{|l|l|l|}
\hline
1    & 2    & 3 \\
\hlineX[1pt][2pt]{1pt}
4    & 5    & 6 \\
\hline
\end{tabular}
\end{document}

• Thank you. I'm using TeX now for little more then a year and am still learning. There are so many little details. Jan 4 at 22:54

The answer of muzimuzhi Z shows what you should do to avoid the error (and you should probably accept that one) but your actual question asks why it loops rather than how to avoid the error.

The looping isn't really related to xparse other than looking for an optional argument is not allowed before \specialrule (or \hrule or \multicolumn or \rowcolor or similar special table cell commands) If any non-expandable material is seen the cell template starts and it is too late to insert the non-aligned material for the rule.

So a simpler example of the loop is

\documentclass{article}

\usepackage{booktabs}

\begin{document}

\tracingall
\begin{tabular}{|l|l|l|}
\hline
1    & 2    & 3 \\
\relax\specialrule{0pt}{0pt}{1pt}
4    & 5    & 6 \\
\hline
\end{tabular}
\end{document}


As in your example this stops with several essentially spurious error messages but if you scroll past them you eventually hit a tight loop and will have to kill the program, \tracingall will show:

.
.
.
\par ->
{\hrule}

\par ->
{\hrule}

\par ->
{\hrule}
.
.
.


Which shows that essentially you have hit this well known loop condition:

\documentclass{article}

\begin{document}

{\let\par\relax x\hrule}

\end{document}


Which makes TeX run forever with no error.

\hrule, which makes a horizontal line across the page is only allowed between paragraphs, in vertical mode. If it is encountered in horizontal mode TeX does not raise an error it inserts \par to end the current paragraph before the \hrule token then proceeds as normal.

The thing to note is that unlike the similar situation of a vertical box ending in horizontal mode, TeX does not execute the primitive end-paragraph code, it literally inserts the token \par into the input stream.

So if as here (and for technical reasons in latex tabular) \par is locally defined to do nothing then \hrule triggers insertion of \par which does nothing, then the \hrule is seen again, which inserts \par....

• Ah, the magic \par token .... not perhaps the most brilliant plan in TeX Jan 4 at 21:46
• @JosephWright no, that accolade goes to \outer Jan 4 at 21:49
• Thank you very much for your explanation. I'm satisfied. I try further hacking with this and see what's happening. Jan 4 at 22:53