9

Let me give a bit of background before the actual questions. I took a look at latex.ltx to see how labels are handled. I found that:

\def\label#1{\@bsphack
  \protected@write\@auxout{}%
         {\string\newlabel{#1}{{\@currentlabel}{\thepage}}}%
  \@esphack}

defines \label as essentially writing a \newlabel command to the .aux file. Let me crack this. \protected@write is as follows:

\long\def \protected@write#1#2#3{%
      \begingroup
       \let\thepage\relax
       #2%
       \let\protect\@unexpandable@protect
       \edef\reserved@a{\write#1{#3}}%
       \reserved@a
      \endgroup
      \if@nobreak\ifvmode\nobreak\fi\fi
}

This is an interesting reading on \let\thepage\relax, which will probably also justify the grouping. #2 is empty in \label so who cares. The name of \@unexpandable@protect is self-explanatory, as \def\@unexpandable@protect{\noexpand\protect\noexpand} confirms. Next is \@auxout, which is the current .aux file, i.e. either \@mainaux or \@partaux if we are in the middle of an included file. So we understand everything of this \label, save for \@bsphack and \@esphack. This and this explain them. Then I see that in an .aux file of mine I actually find:

\newlabel{thm:defi:SM}{{1.2.1.1}{2}{Spazio Metrico}{defi.1.2.1.1}{}}

Why are there 5 arguments in the second brace pairs, when \label is defined to only write two such, and how are they used, I wonder. So I try reading \ref:

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstoftwo{#1}}

Incidentally, I see \pageref which is the same as \ref save for having \@secondoftwo instead of \@firstoftwo. \@setref is:

\def\@setref#1#2#3{%
  \ifx#1\relax
   \protect\G@refundefinedtrue
   \nfss@text{\reset@font\bfseries ??}%
   \@latex@warning{Reference `#3' on page \thepage \space
             undefined}%
  \else
   \expandafter#2#1\null
  \fi}

If the label is undefined, the \csname r@#1\endcsname passed to \@setref by \ref is \relax, so in that case we have the output of bold ?? (with some font commands I didn't bother to decipher) and the warning, otherwise we have #2#1. #2 is either \@firstoftwo or \@secondoftwo depending on whether \@setref is called by \ref or \pageref. #3 is the label, and is used only in the warning message. What defines \csname r@#1\endcsname? Because the remainder of \@setref is \expandafter#2#1\null, and \null is simply an empty \hbox, probably a separation from what follows to avoid unwanted interactions. So we go into \newlabel:

\def\newlabel{\@newl@bel r}
\@onlypreamble\@newl@bel

\def\@newl@bel#1#2#3{{%
  \@ifundefined{#1@#2}%
    \relax
    {\gdef \@multiplelabels {%
       \@latex@warning@no@line{There were multiply-defined labels}}%
     \@latex@warning@no@line{Label `#2' multiply defined}}%
  \global\@namedef{#1@#2}{#3}}}

Assuming the warnings are handled correctly, just like the \@ifundefined, this should be emitting a warning if the r@#1 is already defined and doing nothing if it isn't, and anyway doing that \@namedef, which is:

\def\@namedef#1{\expandafter\def\csname #1\endcsname}

Here is the definition of \csname r@<label>\endcsname: it's the #3, which was the #2 of \newlabel (or rather, what seems to be #2 of \newlabel at user - or rather .aux - level), which is {{\@currentlabel}{\thepage}}. So that is what goes into \csname r@<label>\endcsname. \@currentlabel starts out false and then is modified during the processing of the document, so following its changes is basically impossible. The question, however, still remains: how do I get the 5 brace pairs in the pseudo-#2 of \newlabel and how come I don't see them in the output if we only have \@firstoftwo and \@secondoftwo rather than \@firstoffive or the likes? The answer lies in hyperref, which \lets \ref to:

\def\HyPsd@ref#1{\HyPsd@@ref#1*\END}%
\def\HyPsd@@ref#1*#2\END{%
  \ifx\\#2\\%
    \HyPsd@@@ref{#1}%
  \else
    \expandafter\HyPsd@@@ref
  \fi
}%
\def\HyPsd@@@ref#1{%
  \expandafter\ifx\csname r@#1\endcsname\relax
    ??%
  \else
    \expandafter\expandafter\expandafter
    \@car\csname r@#1\endcsname\@nil
  \fi
}

Incidentally, it does something similar with \pageref. #2 of \HyPsd@@ref is passed as an empty argument, which gives true in the conditional and makes LaTeX execute \HyPsd@@@ref{#1}, #1 being the argument of \HyPsd@ref which is what \ref is \let to. By the way, \label is \let to \@gobble whenever the above \let happens, so where does \csname r@<label>\endcsname come from? thmtools maybe? Well we will get to that later. Assuming that that cs is defined as before, save for it having all 5 of the brace pairs seen in the \newlabel way above, we see that if the cs is undefined, ?? is outputted, otherwise the cs is made to be produced and expanded by \expandafters in the appropriate number, and then is passed to @car…\@nil, which does the \@firstoffive I expected. The alternate \pageref probably makes use of \@cbr, which is the same as \@car only it takes the second argument. So now I know how the arguments are handled in a pdf string, since I see the \lets above described happen in \pdfstringdef. Theorems are examples of usage of pdf strings, and are what actually interests me, as has probably been between the lines this whole time. I use thmtools. So now the question is: what does the label= key do exactly?

Summing up, the questions are:

  1. What exactly does the label= key of the thmtools package do? Does it use \label internally?
  2. What are those 5 brace pairs? They seem to be {ctr sequence associated with the theorem}{page on which the theorem starts}{theorem name= key}{theorem ctr name.ctr sequence}{empty}. Is this general? And what is the use of the empty brace pair?
  3. How are the extra 3 "parameters" used?

Update: Taking a look at another .aux, I noticed something similar with an equation's label. I also saw this at the top:

\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
\global\let\oldcontentsline\contentsline
\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
\global\let\oldnewlabel\newlabel
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}

So at the start of the document, \newlabel itself is redefined, making it gobble the extra "parameters". This makes the question even more pressing: what are those parameters for? And it also opens a new question: why is \newlabel then re-\let to the old meaning \AtEndDocument? And under what conditions does that redefinition take place? What is that \hyper@anchor? But maybe I'm asking too many questions.

  • Yes, label= uses \label. The \label command is modified by hyperref to write out more than with the normal setting. I don't think that thmtools has something to do with this: it just emits \label{...} at some suitable point during its working. – egreg Nov 27 '14 at 21:51
  • @egreg but why does hyperref want the extra stuff? And does it ever use it in any way? – MickG Nov 27 '14 at 21:53
7

Let's examine a simple document.

\documentclass{article}
\usepackage{amsthm,thmtools}
\usepackage{hyperref}

\declaretheorem{theorem}

\begin{document}

\section{A section title}\label{sec-a}

\begin{theorem}[label=thm-e]
$0\ne1$
\end{theorem}

\begin{theorem}[name=Key theorem,label=thm-key]
$0=0$
\end{theorem}

\end{document}

enter image description here

The \newlabel entries we find in the .aux file are

\newlabel{sec-a}{{1}{1}{A section title}{section.1}{}}
\newlabel{thm-e}{{1}{1}{}{theorem.1}{}}
\newlabel{thm-key}{{2}{1}{Key theorem}{theorem.2}{}}

If hyperref is not used, the entries will be different:

\newlabel{sec-a}{{1}{1}}
\newlabel{thm-e}{{1}{1}}
\newlabel{thm-key}{{2}{1}}

So we see that hyperref extends the data written out in the .aux file. The second argument to \newlabel contains five brace pairs:

  1. counter's value
  2. page number
  3. title
  4. anchor for hyperlinks with \ref
  5. empty (reserved for future extensions)

The title field is used for \nameref; when you use name=... in the optional argument to \begin{theorem}, you can also use \nameref{thm-key} and the name will be printed, just like for \nameref{sec-a}.

Note that thmtools doesn't make anything special. With the input

\documentclass{article}
\usepackage{amsthm}
\usepackage{hyperref}

\newtheorem{theorem}{Theorem}

\begin{document}

\section{A section title}\label{sec-a}

\begin{theorem}\label{thm-e}
$0\ne1$
\end{theorem}

\begin{theorem}[Key theorem]\label{thm-key}
$0=0$
\end{theorem}

\end{document}

the annotations in the .aux file would be identical:

\newlabel{sec-a}{{1}{1}{A section title}{section.1}{}}
\newlabel{thm-e}{{1}{1}{}{theorem.1}{}}
\newlabel{thm-key}{{2}{1}{Key theorem}{theorem.2}{}}

The label=thm-e key in the optional argument is simply translated into \label{thm-e} during processing of \begin{theorem}.


The code

\providecommand\hyper@newdestlabel[2]{}
\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
\global\let\oldcontentsline\contentsline
\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
\global\let\oldnewlabel\newlabel
\gdef\newlabel#1#2{\newlabelxx{#1}#2}
\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
\AtEndDocument{\ifx\hyper@anchor\@undefined
\let\contentsline\oldcontentsline
\let\newlabel\oldnewlabel
\fi}
\fi}

is a safeguard for the case when an .aux file has been written with hyperref loaded and then the file is reprocessed without hyperref. When the .aux file is read at begin document, in this case, the extra argument would confuse LaTeX, so the \newlabel command is temporarily redefined to do what it normally does without hyperref and the extra arguments are swallowed.

After having read the .aux file at begin document, LaTeX reopens the file for writing, so producing a fresh version.

A similar treatment is used for \contentsline.

  • Just one thing: is there any command using the fourth parameter @egreg? – MickG Nov 28 '14 at 9:25
  • 1
    @MickG No, as far as I know; Heiko introduced it as a hook for future extensions. – egreg Nov 28 '14 at 9:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.