# Why does this macro break with Lastpage?

I have made a macro \@Romankern that makes roman numerals with a negative kerning between them to make them closer to each other. I named it \@Romankern to allow it to be used with \pagenumbering.

The macro works fine until I load the lastpage package. When this package is loaded the macro breaks telling me:

! Undefined control sequence.
\@Romankern #1->\edef \temp
{\@Roman {#1}}\expandafter \@romkern \temp ...


I tried to trace the source of the error but failed... miserably. What is wrong with my macro that it is so fragile?

\documentclass{article}

\usepackage{lipsum}
\usepackage{lastpage}

\makeatletter

\def\@Romankern#1{%
\edef\temp{\@Roman{#1}}%
\expandafter\@romkern\temp\@empty}
\def\@romkern#1#2{%
\ifx#2\@empty
#1%
\let\next\relax
\else
#1\kern-0.07em%
\let\next\@romkern
\fi
\next#2}

\begin{document}

\pagenumbering{Romankern}

\lipsum[1-50]

\end{document}


The definition of \@Romankern is not robust, because it contains assignments (\def\temp{...}, \let\next\@romkern, ...). If the label is written to the .aux file, assignments are not carried out and \def\temp{...} becomes to something like \def<the expansion of \temp>{...} with <the expansion of \temp> being the result of expanding the current meaning of \temp. In the case of the question \temp is undefined and therefore raises an error.

The following example defines a macro \@@Romankern that takes a plain number as argument and that will go to the .aux file. The conversion of the argument of \@Romankern, a counter value, to a plain number is done in an expandable and therefore robust way (via \expandafter and \number). The macro \@@Romankern is made robust by e-TeX's \protected that prevents the expansion of \@@Romankern, when writing to the .aux file.

\documentclass{article}

\usepackage{lipsum}
\usepackage{lastpage}

\makeatletter
\def\@Romankern#1{%
\expandafter\@@Romankern\expandafter{\number#1}%
}
\protected\def\@@Romankern#1{%
\edef\temp{\@Roman{#1}}%
\expandafter\@romkern\temp\@empty\@empty
}
\def\@romkern#1#2{%
\ifx#2\@empty
#1%
\let\next\relax
\else
#1\kern-0.07em%
\let\next\@romkern
\fi
\next#2}

\begin{document}

\pagenumbering{Romankern}

Last page: \pageref{LastPage}

\lipsum[1-50]

\end{document}


The .aux file contains:

\relax
\newlabel{LastPage}{{}{\@@Romankern {10}}}
\xdef\lastpage@lastpage{\@@Romankern {10}}
\gdef\lastpage@lastpageHy{}


Remarks:

• The call of \@romkern in

\def\temp{\@Roman{#1}}%
\expandafter\@romkern\temp\@empty\@empty


is modified to contain two stop tokens \@empty, because \@romkern always expects two arguments. But \temp is empty for zero or negative numbers.

• Ooh, now I understand it. Excellent explanation. Thanks a lot :) – John Doe-Nut Apr 8 '18 at 1:12