1

Some examples to show how LaTeX deals with macro inside the chapter/section title

Example 1

A very basic LaTeX chapter and reference process goes like this

\documentclass{book}
\usepackage{hyperref}

\begin{document}
    \frontmatter
    \tableofcontents
    \mainmatter
    \chapter{Chap}\label{expansion_test}
    \nameref{expansion_test}
\end{document}

This will end up with the following line in the .aux file

\newlabel{expansion_test}{{1}{1}{Chap}{chapter.1}{}}

and in the .toc file

\contentsline {chapter}{\numberline {1}Chap}{1}{chapter.1}%

Everything works fine now.

Example 2

But, when one tries to use some complex macro in place of the plain text chapter title, like

\documentclass{book}
\usepackage{hyperref}
\newcommand{\expansiontest}[1][]{
    expansiontest~#1
}

\begin{document}
    \frontmatter
    \tableofcontents
    \mainmatter
    \chapter{\expansiontest[Chap]}\label{expansion_test}
    \nameref{expansion_test}
\end{document}

One would then find that the title/name part of the above two lines will now be unexpanded macro, like

\newlabel{expansion_test}{{1}{1}{\expansiontest [Chap]}{chapter.1}{}}
\contentsline {chapter}{\numberline {1}\expansiontest [Chap]}{1}{chapter.1}%

In this example, everything is still fine.

Example 3

But when one tries to include some user-defined counter in this complex macro, then things will become very ugly.

\documentclass{book}
\usepackage{hyperref}
\newcounter{SomeCounter}[chapter]
\renewcommand{\theSomeCounter}{\thechapter.\arabic{SomeCounter}.}
\newcommand{\expansiontest}[1][]{
    \theSomeCounter~expansiontest~#1
}

\begin{document}
    \frontmatter
    \tableofcontents
    \mainmatter
    \chapter{\expansiontest[Chap]}\label{expansion_test}
    \refstepcounter{SomeCounter}
    \nameref{expansion_test}
\end{document}

This macro will not be expanded in the .aux and .toc files as before. But this will now cause some trouble.

  • In the chapter title, one would find the counter displayed as 1.0 since it is located in Chapter 1 and no \refstepcounter{SomeCounter} command preexists. This is the desired display!

  • Since the table of content is in chapter 0 and no \refstepcounter{SomeCounter} command preexists ToC either, thus in the ToC one would find the counter displayed as 0.0.

  • For the reference in the end, one would find the counter displayed as 1.1 because we have implemented a \refstepcounter{SomeCounter} before this \nameref.

Example 4

If one further include the \refstepcounter{SomeCounter} line in the definition of the \expansiontest macro to get some automatation.

\documentclass{book}
\usepackage{hyperref}
\newcounter{SomeCounter}[chapter]
\renewcommand{\theSomeCounter}{\thechapter.\arabic{SomeCounter}.}
\newcommand{\expansiontest}[1][]{
    \refstepcounter{SomeCounter}
    \theSomeCounter~expansiontest~#1
}

\begin{document}
    \frontmatter
    \tableofcontents
    \mainmatter
    \chapter{\expansiontest[Chap]}\label{expansion_test}
    \nameref{expansion_test}
\end{document}

One would find the counters displayed as

  • in the chapter title, 1.1

  • in the ToC, 0.1

  • in the reference in the end, 1.2

My questions

  1. So, what is the exact line where LaTeX stop expanding the macro when writing to those various auxilliary files? In example 2, if one changes the optional argument to the mandatory one, then one would still find expanded macro in both .aux and .toc files. But if one further include a italic format macro as

    \newcommand{\expansiontest}[1]{
        \textit{expansiontest~#1}
    }
    

    Then in the .toc file we would still find the expanded commands, but in the .aux we would now find unexpanded macro.

  2. My mid-term motivation to investigate this problem is to get the same displaies in the ToC and references as in the original chapter title when the chapter title is expressed in macro. The problem is not unique to the use of user-defined counters. One may also redefine the macro \expansiontest anywhere to find inconsistencies. So, can we and how we achieve this?

  3. My final aim is to define a new counter and a macro with the following functionalities.

    • Increase this new counter by one everytime it is called.
    • Then display the current counter followed by some text from the argument of that macro.
    • There may also be some user-defined formats, like italic style, specific color, boxed, et al.
    • This new macro can display the counter correctly in ToC and reference when used in the chapter/section title.
    • This macro will also be used outside of the chapter/section title, ie, in the ordinary text. And counter inside and outside the chapter/section title must be the same one. I'm not expecting to define two independent counters.

    So, how to achieve those aims?

    My current solution is as follows. But it will cause this chapter/section title problem.

    \newcounter{SomeCounter}[chapter]
    \renewcommand{\theSomeCounter}{\thechapter.\arabic{SomeCounter}.}
    \newcommand{\SomeCounterName}{A name}
    \newcommand{\SomeMacro}[1][]{%
        \refstepcounter{SomeCounter}%
        \ifthenelse{\isempty{#1}}{\let\@currentlabelname\@currentlabel}{\NR@gettitle{#1}}%
        {\bfseries\defclr{\setlength{\fboxrule}{0.25ex}\setlength{\fboxsep}{0.5ex}\fbox{\SomeCounterName~\theSomeCounter{}}}\ifthenelse{\isempty{#1}}{}{~(#1)}}%
    }
    
4
  • Simply put: commands defined with \newcommand to have an optional part are not expanded during \protected@write (which is what LaTeX uses for the jobs you're interested in). Take or leave.
    – egreg
    Aug 30, 2022 at 17:39
  • You can use \protect to prevent a specific macro from being expanded (until printed). Some macros (\like \label) are automatically deactivated, at least some of the time. Aug 30, 2022 at 22:30
  • Distinguish expandable stuff from unexpandable stuff. Expansion is done in TeX's gullet. Assignments are done in TeX's stomach. With example 4 using \expansiontest within the (moving) argument of \chapter in any case does not work out because \expansiontest calls \refstepcounter which implies assignments which do not get carried out during expansion, but writing moving-argument implies expansion and then writing and (!)not carrying out(!) unexpandable tokens. If no other things would go wrong in any case the counter-stepping would be repeated wherever the moving argument was typeset. Aug 31, 2022 at 3:23
  • My final aim is to define a new counter and a macro with the following functionalities. Increase this new counter by one everytime it is called. This is not precise. What does "calling a macro" mean exactly? If you use a macro within a moving argument, e.g., the argument of the command \chapter, the argument is automatically replicated e.g., in the table of contents, in the bookmarks, when doing \nameref, in the page-headings if \pagestyle{headings} is in effect. Do you wish incrementing the counter with each of these repeated instances as well? Aug 31, 2022 at 20:28

1 Answer 1

1

I think your question about the "exact point" at which LaTeX stops expanding the macro when it is written to these various auxiliary files is hard to answer.

When writing tokens to external text files, the LaTeX 2ε-kernel provides and uses various mechanisms to prevent or to time the expansion of certain macros.

Whether these mechanisms are used/applied/taken into account with a macro is up to the programmer who writes the macro.

Timing control is necessary because, for example, some information, especially the page number, is not available until enough material for a page has been accumulated and typeset and the output routine ejects the page, hereby adjusting the value of the page counter.

So if you also wish to have the page number written to an auxiliary file, as is the case with cross-referencing-labels, for example, the writing needs to be delayed until the page is dumped to the .dvi- or .pdf-file.

Thereby it can make a difference whether tokens representing what is to be written are expanded immediately or at the moment of page ejection, because between these two points in time there is a time span during which e.g. control sequences can be redefined/can get a different meaning which in turn affects the result of expansion and thus affects what is written.

Expansion prevention is necessary, for example, when transferring information from one auxiliary file to another whereby the set of characters, which after tokenization forms the tokens which represent that information, should not be changed. E.g., sectioning-commands like \chapter, \section etc internally use \addcontentsline/\addtocontents for having TeX write an instruction to the .aux-file. That instruction is a \@writefile-directive for having TeX write things to another auxiliary-file, e.g., the .toc-file (table of contents) or the .lot-file (list of tables) or the .lof-file (list of figures). \@writefile-directives are carried out when the .aux-files are processed at the end of the LaTeX run while, due to commands like \tableofcontents or \listoftables or \listoffigures, which internally use \@starttoc, the corresponding \write-handles are allocated and the corresponding output-files are assigned to these \write-handles and are open for writing. So here you have the scenario of transferring information from the .aux-file to the .toc/.lot/.lof-file.

The LaTeX 2ε-kernel, and thus the mechanisms for temporal expansion control and expansion prevention, have been developed over time. Not every older package uses mechanisms added later.

Explaining the most important mechanisms for expansion-control nowadays present in the the LaTeX ε-kernel might help getting an overview.

But you need a rough overview of how things work in the TeX program in general. These are not things that are specific to the LaTeX 2ε-kernel, but things that are explained e.g. in the TeXbook, which in turn came into being along with the TeX program at a time when no LaTeX format existed yet.

In the TeXbook Donald E. Knuth makes an analogy between the ways in which TeX works and the ways in which the digestive processes of a beast with eyes and digestive tract work.

The eyes look at the .tex-input-file line by line. After looking at a line of .tex-input they move the characters of that line of .tex-input into the mouth.
("look and move" here means

  • copying the characters seen in the line of .tex-input-file to some area of memory managed by TeX,
  • converting from the computer-platform's character-encoding to the TeX-engine's internal character-encoding,
  • removing all space-characters at the right end of the line,
  • attaching at the right end of the line a character whose code-point-number in the TeX-engine's internal character-encoding-scheme equals the value of the integer-parameter \endlinechar. Usually that value is 13 while 13 denotes the return-character in the TeX-engine's internal character-encoding-scheme. With traditional TeX-engines the internal-character-encoding-scheme is ASCII. With TeX-engines based on XeTeX or LuaTeX the internal character-encoding-scheme is unicode/utf-8 whereof ASCII is a strict subset. )

The mouth takes these input-characters for a set of instructions for producing tokens (control-sequence-tokens, character-tokens) and sending these tokens down the gullet. (The mouth divides the "stream of input-characters" produced by the eyes into small bites and according to these bites produces tokens (control-sequence-tokens, character-tokens) and sends these tokens down the gullet which implies that in the gullet you have a "stream of tokens"/a "token-stream".)

In the gullet expansion of expandable tokens, e.g. macros, takes place. This means expandable tokens get removed from the token-stream and replacement-tokens (if there are any) are inserted into the token-stream. This happens (in some sort of regurgitation-process) until there are no expandable tokens left in the token-stream. The tokens that result from expanding expandable tokens in the gullet are send to TeX's stomach. Thus usually only unexpandable tokens reach TeX's stomach.

I wrote "usually" here because there are exceptional circumstances where expansion is suppressed so that expandable tokens can reach the stomach:
E.g., when the stomach requests tokens from the gullet that shall belong to the ⟨parameter text⟩ or the ⟨balanced text⟩ of a \def-assignment, expansion is suppressed. With the ⟨balanced text⟩ of an \edef-assignment expansion is not suppressed. E.g., with the tokens belonging to the ⟨balanced text⟩ of a token-register-assignment expansion is suppressed. (But with token-register assignments expansion is not suppressed until finding the left brace { before the ⟨balanced text⟩, which in turn is trailed by ⟨right brace⟩.)

The stage of expansion, which takes place in TeX's gullet, is only about replacing tokens in the token stream by other tokens. Nothing else.

In the stomach and the digestive organs behind the stomach processing of unexpandable tokens takes place.

Processing unexpandable tokens beneath other things subsumes actions like

  • Creating and placing boxes, breaking paragraphs into lines, distributing lines across pages and other typesetting work like adding headers and/or footers with things like page-numbers and sectioning-headings to pages and ejecting pages to .dvi- or .pdf-output-file.

  • Writing special directives to the .dvi- or .pdf-output-file, e.g., for setting up "infrastructure" like bookmarks or hyperlinks and named destinations/targets/anchors within the pdf-file.

  • Writing messages to screen, writing things to external text files, e.g., .aux-file, .toc-file, .log-file/terminal/screen.

    Like \def, which—if in the stomach being taken for something that is to be carried out—triggers TeX's gullet into suppressing expansion of subsequent tokens belonging to the assignment, \write is an interesting thing, too:

    The way in which \write works depends on whether the token \write is preceded by the token \immediate:
    If \write is preceded by \immediate, tokens are written to file immediately whereby expandable tokens are expanded immediately.
    If \write is not preceded by \immediate, tokens are saved away without being expanded until shipping out/ejecting a page to the .dvi-file or .pdf-file the next time. Writing and hereby expanding expandable tokens takes place when shipping out/ejecting the page in question takes place.
    If \write is not preceded by \immediate, there is a time-span between the moment when tokens are saved away and the moment when due to shipping out/ejecting the page tokens are expanded and written. Within this time-span tokens to be written can be redefined leading to getting a different result when writing takes place.

  • Performing assignments. E.g.,

    • Assigning values/content to registers or TeX-parameters.
      Registers may, e.g., be count-registers, token-registers, ... .
      A TeX-parameter adjusts some behavior of TeX. E.g., \escapechar is a TeX-parameter. Writing to screen/external file takes place at a time when TeX already works on tokens. The value of \escapechar plays an important rôle when writing a control sequence token or when delivering via \string or \detokenize the "text representation" of a control-sequence token—the "text representation" of a control-sequence token consists of explicit character-tokens of category 12(other) except that spaces are of category 10(space): The value of the TeX-parameter \escapechar denotes the character-code [= the number of the codepoint of the corresponding character in TeX's internal character encoding scheme] of the character-token which is to be prepended to the sequence of character tokens that represent the name of the control sequence token in question. Usually the value of \escapechar is 92 while both in unicode and in ASCII the code point number 92 denotes the backslash-character \.

    • Macro-definitions in terms of \def/\edef/\gdef/\xdef.
      \def/\edef/\gdef/\xdef assign a replacement-rule to a control sequence token. They "instruct" TeX to henceforth in the gullet/during the stage of macro expansion (in situations where expansion is not suppressed) remove from the token stream the control sequence token in question and subsequent tokens according to the assignment's parameter text and to insert into the token-stream some set/sequence of tokens according to the assignment's definition text when encountering the control-sequence-token to which the replacement-rule is assigned. \def/\edef/\gdef/\xdef focus on the behavior of TeX's gullet/focus on the beavior during the stage of expansion.

    • Assignments in terms of \let or \futurelet.
      A \let-assignment is not a replacement-rule. A \let-assignment does not focus exclusively on changing the behavior of TeX's gullet. A \let-assignment can affect the behavior of digestive organs behind the gullet as well: \let\BBB=\AAA "tells" TeX: "When encountering \BBB in a way where \BBB is to be carried out—e.g., not when applying \string/\detokenize to \BBB, not when removing \BBB as the delimiter of a delimited macro argument, not when unexpanded-writing \BBB to screen/text-file, not when gathering without expansion the tokens for the definition-text of a macro-assignment—behave in the way in which you would have behaved when instead encountering \AAA (while the meaning of \AAA was still unchanged)." After \let\BBB=\AAA carrying out \BBB triggers the actions which at the time of performing the \let-assignment would have been triggered by carrying out \AAA. If you say \let\BBB=\hbox then \BBB can be used to instruct TeX to construct a box whose content is to be typeset in restricted horizontal mode. This is something that does not take place in the gullet but takes place in the stomach. If you afterwards say \def\hbox{You should not do this}, then \BBB can still be used for this purpose but \hbox cannot be used for this purpose any more because now \hbox has been assigned a replacement-rule/because \hbox has become a macro which during the stage of expansion in the gullet is removed from the token-stream and replaced by character-tokens that represent the phrase You should not do this.

      \futurelet⟨single control sequence that shall obtain a new meaning⟩
                ⟨single token to process when assignment is done⟩
                ⟨single token whose current meaning is to be copied⟩
      is like
      \let⟨single control sequence that shall obtain a new meaning⟩=
          ⟨single token whose current meaning is to be copied⟩
          ⟨single token to process when assignment is done⟩
          ⟨single token whose current meaning is to be copied⟩
      or like
      \afterassignment⟨single token to process when assignment is done⟩
      \let⟨single control sequence that shall obtain a new meaning⟩=
          ⟨token whose current meaning is to be copied⟩
          ⟨token whose current meaning is to be copied⟩

 

LaTeX-commands like \newcommand/\renewcommand/\DeclareRobustCommand/\ProvideCommand or \NewDocumentCommand are just tricky macros which during expansion "decompose" into directives to perform macro-definitions in terms of TeX's \def-primitive. If there are optional arguments, these directives place instructions into the replacement-texts of the to-be-defined control-sequences for "looking ahead" at the next token in the token-stream for finding out if there is a [/a left square bracket.
Looking ahead at the next token in the token stream with "oldschool" TeX-engines is possible in a reliable way only when also invoking \let or \futurelet, which in turn are assignments. (A lot of things can be done by examining macro-arguments by means of expansion-methods in the gullet only, but the way in which undelimited macro arguments are grabbed from the token stream makes it impossible to reliably crank out only by expansion methods the case of the next arbitrary token in the token stream being a space token or a curly brace {1/}2. \NewExpandableDocumentCommand, which formerly was provided via the package xparse and nowadays is part of the LaTeX 2ε-kernel, is an attempt at detecting optional arguments only by methods based on expansion, but the xparse-manual reveals that, e.g., \test[optional]{mandatory} is treated the same as \test{[}optional]{mandatory}. With LuaTeX you can implement expandable look-ahead by means of Lua-routines but when LaTeX and the macro \newcommand were invented, there was no LuaTeX yet.)
The circumstance that the look-ahead at the next token for detecting the presence o a [ with commands defined in terms of \newcommand/\renewcommand/\DeclareRobustCommand/\ProvideCommand is implemented by means of \futurelet implies that expanding macros which process optional arguments defined via \newcommand/etc also yields tokens for performing assignments that are needed for the look-ahead for detecting the presence of an optional argument. These assignment-tokens won't be carried out in the gullet. They make it into the stomach. This in turn implies that such macros don't work out in situations where all the work must be performed only in the gullet. I.e., such macros don't work out in pure expansion contexts.

\edef/\xdef/\write and the like are such pure expansion-contexts:

If you define

\def\innermacro{X}%
\def\something{Y}%
\def\macro{\def\innermacro{\something}}%

and say

\newwrite\myfile
\immediate\openout\myfile foobar.txt %
\immediate\write\myfile{\macro}%
\immediate\closeout\myfile

, then stuff gets expanded right before actually writing to foobar.txt, which in turn with \immediate happens immediately.

The crucial/subtle point is:

When a \def reaches the stomach for being carried out, TeX "tells" the gullet to suppress expansion while sending to the stomach the tokens that form the other tokens/components of the assignment.

But —as said above—at the time of actually writing things expansion takes place and the expansion of \macro yields the tokens \def\innermacro{\something}. The token \def in turn is not expandable and in this situation is not considered a token that is to be carried out but is considered a token that is to be written. Thus expansion is not suppressed with subsequent tokens. Thus \innermacro is expanded as well, yielding X. X in turn is unexpandable and is written, too. Then {, which is unexpandable, is written. Then \something is expanded, which yields Y, which in turn is not expandable and is written. Then }, which is unexpandable, is written. All in all \immediate\write\myfile{\macro} yields writing to file the sequence \def X{Y}, which probably is not what was intended. Analogously, if you say \edef\foobar{\macro}, this is like saying \def\foobar{\def X{Y}}: The \def coming from expanding \macro is unexpandable and is not recognized as a token that shall be carried out, so it makes it into the replacement-text of the \edef-assignment without causing TeX to suppress expansion of subsequent tokens.

Such things are the reason why in LaTeX 2ε expansion-prevention in terms of the "oldschool"-\protect-mechanism was invented:

You can say \def\protect{\noexpand\protect\noexpand}...\immediate\write\myfile{\protect\macro} and this yields writing the sequence \protect\macro.
When the file is read back while \let\protect=\relax is in effect, \protect is the same as the stomach's \relax-no-op-primitive and \macro is expanded as usual.
When you say \let\protect=\string and have TeX write \protect\macro to screen, \macro is stringified and you get written on the screen the character-sequence \macro.
With the LaTeX 2ε-kernel the macro \@unexpandable@protect expands to \noexpand\protect\noexpand.
With the LaTeX 2ε-kernel the macro \@typeset@protect is \let equal to \relax.

Temporarily (re)defining the token \protect by \letting that equal to \@unexpandable@protect before doing \edef and \letting the token \protect equal to \@typeset@protect/\relax after doing \edef is done under the hood with LaTeX 2ε's \protected@edef and \protected@write.

\protected@write is like doing \protected@edef and passing the result as an argument of a delayed (not \immediate) \write.

With the replacement-texts/arguments of \protected@edef and \protected@write the prepending of the token \protect can be done manually.
With macro-tokens defined in terms of \DeclareRobustCommand (in any case) or \newcommand/\renewcommand/\providecommand (only in case optional arguments shall be processed) the prepending of the token \protect is done under the hood automatically.

Besides the "oldschool"-\protect-mechanism there is a newer thing, also:

Newer/extended TeX-engines come along with a builtin-prefix \protected for \def/\edef/\gdef/\xdef-assignments.
Like you can say \global\def... for indicating that the assignment shall not be restricted to the local scope but shall be applied to all super-ordinate scopes also, and like you can say \long\def... for indicating that arguments of the to-be-defined macro may contain the token \par, and like you can say \outer\def... for indicating that the to-be-defined control-sequence may be used neither within the arguments of macros nor within the replacement-text or parameter-text of \def-assignments, the prefix \protected can be used for indicating that the to-be-defined control sequence may not be expanded when expansion is triggered directly by \write or \edef or \xdef or \message or \errmessage or \specialor \mark or \marks or by looking ahead in an alignment for \noalign or \omit or by \directlua. But with things like \write or \edef or \xdef etc expansion of macros defined using the prefix \protected can still be triggered by things like \if / \ifcat / \ifnum / \number / \romannumeral / \expandafter. The prefixes \long, \global, \outer and \protected can be combined.

There are two other subtle very similar mechanisms for preventing expansion:

  • When writing via \write or expanding within an \edef/\xdef something like \the⟨register⟩, then the tokens forming the value/content of the register are delivered but they are not expanded.
  • When writing via \write or expanding within an \edef/\xdef something that is wrapped in \unexpanded{...}, then this is delivered but not expanded.

Be aware that hashes of category 6(parameter) are doubled when delivered by \unexpanded or delivered by \the-expansion of the value of a register during expansion for an \edef/\xdef-assignment and when writing to file and when doing \scantokens. (\scantokens is like wrapping tokens between \unexpanded{...} for writing to file and applying \input to that file, but conversion between the computer-platform's character encoding scheme and TeX's internal character-encoding scheme and hereby applying .tcx-files for character-translation denoting when to write characters in terms of ^^-notation is omitted, which is a good thing.)

The sectioning commands of the standard classes (article, report, book) use \protected@edef for saving the sectioning-titles in scratch-macros for usage when creating headers/footers of pages.

The sectioning commands of the standard classes use \addcontentsline/\addtocontents for handling entries for the .toc-file. \addtocontents/\addcontentsline in turn internally use \protected@write for writing the \@writefile-entry to .aux-file. \@writefile prevents expansion by putting things into a scratch-token-register and writing its \the-expansion.

The sectioning commands of the standard classes use \protected@edef for obtaining and saving cross-referencing-information into unprotected scratch-macros that are used by the \label-command.

When loading hyperref or nameref, the obtaining and saving away into scratch-macros of sectioning titles provided as arguments of sectioning commands for cross-referencing via \nameref is done by macros which come from the package gettitlestring. The macros from the package gettitlestring remove undesired tokens like instances of the \label-command from the arguments of the sectioning commands as it is not desirable, e.g., to have attempts at placing the same cross-referencing-label again and again when repeatedly referencing the same sectioning title.
Hereby two possibilities exist: Either the tokens of the argument which forms the sectioning title are fully expanded via \protected@edef. Or they are not expanded at all and the toplexel-expansion of the scratch-macro provided for usage by the \label-command is protected from further expansion. Not expanding the tokens forming the sectioning title at all and having the toplevel-expansion of the scratch-macro for the \label-command protected from further expansion is the default. If you specify the option expanded when loading gettitlestring, then things are expanded using \protected@edef.

The \label-mechanism of the LaTeX 2ε-kernel in turn uses \protected@write for writing \newlabel{}{...}-entries to .aux-files.

The need of removing things from the argument of a sectioning command because having them repeated is not desired does not only occur with the infrastructure for \nameref-references.
The arguments of sectioning-commands are so-called "moving arguments" because they do not occur only in the place where the section-heading is typeset in the main text but they occur in many other places as well:

  • in the table of contents,
  • in the bookmarks,
  • when doing \nameref,
  • in the page-headers if \pagestyle{headings} is in effect.

The bookmarks require special attention because they belong to the "infrastructure" of the .pdf-file and thus need to be encoded with a character encoding complying to the pdf-standard and understood by the pdf-viewer. \hyperref and the package bookmarks do the conversion under the hood.

Page-headers require special attention because with some page-styles things like \uppercase/\lowercase are performed which then also are applied to character-tokens belonging to names of cross-referencing labels. So if you do a "hyperlinkless" cross-reference within the argument of a sectioning-command, the characters denoting the cross-referencing-label might be transformed by uppercasing/lowercasing before the cross-referencing-command is carried out, yielding an attempt at accessing data of an undefined cross-referencing-label.

\nameref-references require special attention because the scratch-macro \@currentlabelname, which holds the sectioning-title and which is used by \label, is (re)defined before actually typesetting the section-heading within in the main text of the document.

Having said all those things an approach could be a command \expansiontest which processes non-optional arguments only and therefore can be fully expandable in pure-expansion-contexts. Pure-expansion-contexts are indicated by the circumstance of the token \protect not being equal to \@typeset@protect/\relax. If in normal typesetting-mode while not creating a name-string for a pdf-bookmark, i.e., when not preparing in terms of \protected@write or \protected@edef or the like the moving of a moving argument, the command shall step the counter in question via \refstepcounter and place a cross-referencing-label so that the value of the counter current at the time of carrying out this instance of \expansiontest can be retrieved throughout the entire document. In any case - also when preparing the moving of a moving argument, the command shall create a "hyperlinkless" cross-reference to that cross-referencing-label and place the other arguments. This implies that with each instance of \expansiontest you need to provide an argument denoting the unique name of a cross-referencing-label (which then is used internally with moving arguments). If a page-style is in effect where the tokens forming the argument of the sectioning command are transformed, e.g., using something like \uppercase or \lowercase, then the unique names of cross-referencing-labels should be formed by tokens which are not affected by that. E.g., if uppercasing is done you can use uppercase-letters and digits. It is also recommended to stick to ASCII-characters because this might minimize the chance of running into trouble if on an 8bit-engine using the package inputenc for having some character-encoding by making some of the non-ASCII/some of the upper 128 bytes/characters active:

\documentclass{book}
\usepackage[expand]{gettitlestring} % have \nameref-titlephrases expanded by means of `\protected@edef`
                                    % so that the instuction for stepping counter and placing label are
                                    % removed while preparing \@currentlabelname.
\usepackage{hyperref}
\newcounter{SomeCounter}[chapter]
\renewcommand{\theSomeCounter}{\thechapter.\arabic{SomeCounter}.}
\makeatletter
\newcommand{\expansiontest}[2]{%
    \ifx\protect\@typeset@protect
       \texorpdfstring{%
         % A unique cross-referencing-label needs to be placed for each counter stepped here.
         \refstepcounter{SomeCounter}%
         \NR@gettitle{\ref*{#1}~expansiontest~#2}%
         \label{#1}%
        }{}%
    \fi
    \ref*{#1}~expansiontest~#2%
}%
\makeatother

\begin{document}
    \frontmatter
    \tableofcontents
    \mainmatter
    \pagestyle{headings}
    \chapter{some chapter}\label{some chapter}
    \chapter{\label{expansion_test}\expansiontest{EXPANSIONTEST(SOMECOUNTER)(LABEL1)}{Chap}}

    Some text.

    \bigskip

    \noindent
    \expansiontest{EXPANSIONTEST(SOMECOUNTER)(LABEL2)}{Not in chap}

    \bigskip

    \noindent
    Cross-referencing:

    \noindent
    \verb|\nameref{expansion_test}|: \nameref{expansion_test}

    \noindent
    \verb|\ref{expansion_test}|: \ref{expansion_test}

    \noindent
    \verb|\nameref{EXPANSIONTEST(SOMECOUNTER)(LABEL1)}|:
    \nameref{EXPANSIONTEST(SOMECOUNTER)(LABEL1)}

    \noindent
    \verb|\ref{EXPANSIONTEST(SOMECOUNTER)(LABEL1)}|:
    \ref{EXPANSIONTEST(SOMECOUNTER)(LABEL1)}

    \noindent
    \verb|\nameref{EXPANSIONTEST(SOMECOUNTER)(LABEL2)}|:
    \nameref{EXPANSIONTEST(SOMECOUNTER)(LABEL2)}

    \noindent
    \verb|\ref{EXPANSIONTEST(SOMECOUNTER)(LABEL2)}|:
    \ref{EXPANSIONTEST(SOMECOUNTER)(LABEL2)}

    \noindent
    \verb|\nameref{some chapter}|: \nameref{some chapter}

    \noindent
    \verb|\ref{some chapter}|: \ref{some chapter}

    % Some pages so you can see the page headers
    \newpage\null\newpage
\end{document}

enter image description here

You must log in to answer this question.

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