5

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}

1 Answer 1

7

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.

1
  • Ooh, now I understand it. Excellent explanation. Thanks a lot :) Commented Apr 8, 2018 at 1:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .