Why can't I use \edef with \pageref from hyperref?

This works nicely:

\documentclass{article}
\begin{document}
\label{mylabel}
\pageref{mylabel}
\edef\mypage{\pageref{mylabel}}
\end{document}


But using hyperref, thus replacing \pageref by \pageref* to have only the page number without the link, this does not work:

\documentclass{article}
\usepackage{hyperref}
\begin{document}
\label{mylabel}
\pageref*{mylabel}
\edef\mypage{\pageref*{mylabel}}
\end{document}


The error is:

! Undefined control sequence.
l.6     \edef\mypage
{\pageref*{mylabel}}
The control sequence at the end of the top line
of your error message was never \def'ed.


Why is that, and how can I do it better?

• Adding \def\mypage\relax before \edeffixes the error, but then \mypage after \edef raises Use of \mypage doesn't match its definition. \end – bers Oct 4 '16 at 20:10
• if you put \def\mypage\relax there then the full definition is \def\mypage\relax\edef\mypage{\pageref*{mylabel}} and \mypage is defined such that it has to be followed by \relax\edef\mypage and expands to \pageref*{mylabel} (which would generate an error that the generated expand is not followed by \relax the {} are mandatory in \def so it includes all the tokens up the the {} it finds. – David Carlisle Oct 4 '16 at 20:13

Commands taking a *-variant are not expandable, so they can't be used in \edef.

The particular error is not really meaningful; if you go past it and try running LaTeX again, you get

! Undefined control sequence.
\HyRef@StarSetRef ...Hy@safe@activestrue \edef \x


You get what you'd like with refcount and \getpagerefnumber:

\documentclass{article}
\usepackage{refcount}
\usepackage{hyperref}

\begin{document}

\label{mylabel}
\pageref*{mylabel}
\edef\mypage{\getpagerefnumber{mylabel}}

\mypage

\end{document}


The output shows 1 twice as expected.

Using \protected@edef as suggested in another answer is not what you're looking for. Here's an extended example:

\documentclass{article}
\usepackage{refcount}
\usepackage{hyperref}

\begin{document}

\label{mylabel}
\pageref*{mylabel}
\edef\mypage{\getpagerefnumber{mylabel}}

\mypage

\makeatletter
\protected@edef\mypageagain{\pageref*{mylabel}}
\makeatother

\texttt{\meaning\mypage}

\texttt{\meaning\mypageagain}

\end{document}


You can see that \mypageagain doesn't contain the page number.

• Yes, that works! – bers Oct 4 '16 at 20:16
• Also, \refused{mylabel} should be added to get a warning, if mylabel is still undefined. Since a warning will not work in an expandable context like by \edef, it cannot be included in the expandable \getpagerefnumber. – Heiko Oberdiek Oct 4 '16 at 22:02

You can not, in general, use \edef on general latex text, the fact that you do not get an error in the first use is purely by chance. More or less any * command is going to fail as \@ifnextchar does not work by expansion so it will fail in the lookahead for the * irrespective of the command definition.

This is the origin of the "fragile command" distinction in LaTeX and why latex commands should use \protected@edef so \protect is set up to make fragile commands safe before the edef. (But being safe means it may not expand as you need, you did not give your actual use case here)

• Thanks! Basically, I want to compare whether two labels are on the same page, so I thought about storing the expanded \pagerefs in two macros and comparing those... – bers Oct 4 '16 at 20:13
• @bers you can use ifthenelse which locally makes pageref safe while testing (but I wouldn't) or use Heiko's zref suite which is designed for this – David Carlisle Oct 4 '16 at 20:16
• Yes, thanks for that suggestion. I was actually trying to do the same without an extra package (thus, without ifthenelse), so now I just need to choose between that and refcount. The latter is easier because it works the same way with and without hyperref; in the former, I need an additional check for hyperref. – bers Oct 4 '16 at 20:23
• @bers I don't trust the author of ifthen I wouldn't use it personally. – David Carlisle Oct 4 '16 at 20:25