5

This is another question about protection and expansion, that I still don't understand well… (and I guess this is my problem here). I read especially How do I "unprotect" an argument?, and many others.

I'm trying to create automatic and contextual labels for titles (See below for details if needed). If I write eg \myref{My_title_here}, the link to the label is eg “A.II.3.d My title here”, and points to the 4th subsection of the 3rd section of the 2nd chapter in the 1st part. A.II.3.d is the “title number”, and is the result of \getrefnumber {#1} (here #1 is My_title_here), and I want to get it in \templabel, but:

    %\edef \templabel {\getrefnumber {#1}} doesn't work

What I want is to get the result (the expansion) of \getrefnumber {#1} (eg A.II.3.d) in \templabel. Again, the code is at the end if needed.


Workaround

\edef didn't work, so I finally tried \protected@edef (Are \protected\edef and \protected@edef the same?):

    \protected@edef \templabel {\getrefnumber {#1}}
    %\show \templabel->A.\protect \textlatin  {I}.1.

I finally found this to remove \protect:

    \expandafter \expandafter \expandafter \def \expandafter \expandafter \expandafter \templabel \expandafter \expandafter \expandafter {\getrefnumber {#1}}
    %\show \templabel ->A.\textlatin {I}.1.

I looked at the definition of \textlatin and noticed that it really looks like \textbf. It's a formatting command. To remove the \textlatin command, I use the following:

    \def \textlatin #1{#1}

Questions

Finally it works, but:

  1. Can you explain briefly what's the problem here, with protection and expansion? Why can't I use \getrefnumber {#1} directly?

  2. I would like to know is there is a better solution, or more general, or at least, if the solution covers all cases here: how to get directly A.I.1 instead of A.\protect \textlatin {I}.1?

  3. Does this solution with \expandafter works in each case? Which commands may I encounter here, in \getrefnumber {#1}: \textlatin, \textgreek (because I use \greek?) and what else?

  4. The way I deal with the \textlatin command is it the better one? Are there any drawbacks with this solution? (I don't understand the definition of \textlatin, which is like \textbf)

  5. And if I use - instead of . (A-II-3-4)? Does the - will be considered as an arithmetic operation, eg during expansion?

Feel free give advice on code, I'm learning.


The context, just in case

I use the following numbering:

\def \thepart          {\Alph   {part}}
\def \thechapter       {\Roman  {chapter}}
\def \thesection       {\arabic {section}}
\def \thesubsection    {\alph   {subsection}}
\def \thesubsubsection {\greek  {\value{subsubsection}}}
\setcounter {secnumdepth} {3} % Paragraphs and subparagraphs unnumbered

I create “informative” numbering for the titles (Source: (Re)define \ref for chapter that includes the part number):

\def \p@chapter       {\thepart.}
\def \p@section       {\thepart.\thechapter.}
\def \p@subsection    {\thepart.\thechapter.\thesection.}
\def \p@subsubsection {\thepart.\thechapter.\thesection.\thesubsection.}

Then I create my label command that I will patch to sectionning commands (Sources:
Sectioning command that automatically creates label,
Changing the output of \ref depending on the position of the corresponding \label,
How to change the appearance of \ref depending on where it's called relative to the \label,
Automatic creations of labels).

\newcommand {\myref }[1]{%
    \@ifundefined {r@#1} {??} {\begingroup
    %\edef \templabel {\getrefnumber {#1}} doesn't work

To get A.I.2.b in \templabel, this is the problem

Then I will split the string with xstrings:

    \StrCut \templabel         {.} \part@number         \part@tail
    \StrCut \part@tail         {.} \chapter@number      \chapter@tail
    % …
    \StrCut \paragraph@tail    {.} \subparagraph@number \subparagraph@tail

and create the contextual link (the link, his number is eg “A-III-2-b The title here” but if the link is in A-III, it will be only “2-b The title here”; it's contextual):

    \edef \templink {\getrefbykeydefault {#1} {anchor} {}}
    \IfStrEq \thepart \part@number
        {\IfStrEq \thechapter \chapter@number
            %…
            {\textcolor{red}{X} \hyperlink \templink \part@tail}}%
        {\textcolor{red}{X} \hyperlink \templink \templabel}%
    \endgroup}}

The MWE

\documentclass[greek]{book} % THE GREEK OPTION IS THE CAUSE

\usepackage {hyperref}
\usepackage {babel}

\makeatletter
\def \p@chapter       {\thepart.}
\def \p@section       {\thepart.\thechapter.}
\def \p@subsection    {\thepart.\thechapter.\thesection.}
\def \p@subsubsection {\thepart.\thechapter.\thesection.\thesubsection.}

\newcommand {\myref}[1]{%
    \@ifundefined {r@#1} {??} {\begingroup
        \edef \temp {\getrefnumber {#1}}
        % \show \temp->A.\textlatin {I}.1.
        \endgroup }}
\makeatother

\begin{document}
\mainmatter

\part{Hi :\\introduction}\label{Hi}
\chapter{Chapter}\label{Chapter}
See \myref{Test} below.
\section{Test}\label{Test}

\enddocument
  • This looks like pretty aggressive surgery. Are you sure existing packages won't do? E.g., nameref, cleveref, .... – jon Nov 24 '16 at 5:30
  • Can you provide a complete, minimal example? It should start with \documentclass and end with \end{document}. – Werner Nov 24 '16 at 5:39
  • Hi! Thanks for the fast reply! I don't know. I think \getrefnumber {#1} is a command from nameref, which I use. I read the documentation of cleveref, quickly, and others too, but didn't find anything. I prefer not to use too many packages, but if there is one… I'm still interested in the answer here. – user73438 Nov 24 '16 at 5:40
  • @Werner Ok, I start writing it now. I thought the answer could be an evidence. – user73438 Nov 24 '16 at 5:42
  • 1
    The answer to the general question in the title, is "you can't, that's why the command was protected as it will fail in an expansion context" In some special circumstances you can define alternative commands that do work via expansion, but it depends on the exact details of what you want to do. – David Carlisle Nov 24 '16 at 7:44
1

Partial answer, no time for more no.

\getrefnumber comes from package refcount and is full expandable. That means, it can be used inside \edef. But if the reference contains breakable stuff, then \getrefnumber will safely extract this reference, but the reference itself will break. In your case, \textlatin is introduced (probably by babel), which breaks by the hard expansion of \edef.

Since \textlatin is a macro that follows LaTeX's protection protocol, the expansion via \protected@edef is safe as you have observed.

Macros can be protected in LaTeX by \DeclareRobustCommand. Then e-TeX came up, that offers \protected to the definition commands to make a macro robust and prevents expansion in expandable contexts as inside \edef, writing to file.

\protected\edef\macro{definition text} makes a protected \macro and expands the definition text the hard way. \protected@edef makes a normal (unprotected) \macro and expands the definition text with LaTeX's protection mechanism in force.

BTW, if you use the expandable extraction commands of package refcount like \getrefnumber, then \refused should be used with the same label outside the expansion context to get proper warnings for undefined references.

  • Thanks! The comment of @DavidCarlisle complete this answer. I will search information on the differences between the 2 protection mechanisms. What I don't understand is the role of \refused. Could you elaborate? – user73438 Nov 24 '16 at 9:20
  • Throwing a warning is a non-expandable operation in LaTeX. If \getrefnumber is used inside \edef (or \protected@edef), then the warning will become unexpanded garbage and nothing is printed in the screen or .log file. \refused is called outside the expandable context (e.g., before or after the definition with \etex), notifies the user with a warning, if the reference is still undefined, and tells LaTeX that there is an undefined reference. Then LaTeX can print its "rerun" warning at the end of the LaTeX job. – Heiko Oberdiek Nov 24 '16 at 17:35
  • Thanks you! For the record, there is in the first answer, an example of usage : tex.stackexchange.com/questions/252994/… – user73438 Nov 24 '16 at 20:47

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.