I'm reading source2e.pdf and I have problems in understanding the sense of the definition of LaTeX 2ε's \@esphack:
Commands like \label{...} , which themselves do not/shall not produce any visible output, might in the source/in the .tex-input-file be surrounded by spaces. If so, you don't want two space-tokens as this would double the horizontal glue.
If I got it right, \@bsphack and \@esphack are there for avoiding the coming into being of a space-token after tokenizing and processing the command in case there already came one into being before tokenizing and processing the command.
So let's look at the definition of \@bsphack:
> \@bsphack=macro:
->\relax \ifhmode \@savsk \lastskip \@savsf \spacefactor \fi .
l.1 \show\@bsphack
In words:
When in horizontal mode or in restricted horizontal mode, then save the value of \lastskip to \@savsk and save the value of \spacefactor to \@savsf.
Now let's look at the definition of \@esphack:
> \@esphack=macro:
->\relax \ifhmode \spacefactor \@savsf \ifdim \@savsk >\z@ \ifdim \lastskip =\z
@ \nobreak \hskip \z@skip \fi \ignorespaces \fi \fi .
l.2 \show\@esphack
In words:
When in horizontal mode or in restricted horizontal mode, then:
- restore the value of
\spacefactorto the value saved as\savsf. - In case
\@savskis larger than zero, i.e., in case there was some horizontal glue before carrying out the command which at its start called\@bsphack, then do
\ifdim \lastskip =\z@ \nobreak \hskip \z@skip \fi \ignorespaces.
I understand that \ignorespaces will make sense as there was already some horizontal glue before carrying out the command which at its start called \@bsphack.
But I don't understand what the
\ifdim \lastskip =\z@ \nobreak \hskip \z@skip \fi
-part is good for.
What is the sense of this?
In the situation where this is carried out, the saved value in \@savsk is larger than \z@, thus one can conclude that something from within the command which at its start called \@bsphack did change the value of \lastskip to \z@.
But doing something like \nobreak\hskip\z@skip will not revert that change/will not restore \lastskip to its previous value.
Thus: What is the gist/sense/benefit of performing that \hskip of zero-width?
If you wish \lastskip to be restored, shouldn't it then be something like:
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
\ifdim\lastskip=\z@
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\fi
\ignorespaces
\fi
\fi
}%
Or perhaps just
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf %now \spacefactor is restored.
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\ifdim\@savsk>\z@
\ignorespaces
\fi
\fi
}%
Is it possible that in some previous release, it was done this way and in later releases somebody erroneously "optimized" the
\nobreak\hskip-\@savsk\nobreak\hskip\@savsk to \nobreak\hskip\z@skip, overlooking that this won't restore \lastskip any more?
If I understand correctly, you need to restore \lastskip correctly as otherwise things with consecutive sequences of \@bsphack..\@esphack, e.g., \label{foo}\label{bar} won't work correctly:
If by now you do something like
A \label{foo} \label{bar} A
or
A \label{foo}\label{bar} A
, \lastskip will in any case be 0 after \label{foo} which affects the behavior of \label{bar} because with \label{bar} \@savsk will not be larger than \z@ any more so that \ignorespaces won't get carried out although it should be carried out!
With the example below you can see a subtle difference when redefining \@esphack so that it restores \lastskip:
\documentclass{article}
\newsavebox\mybox
\begin{document}
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{1}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{1}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{2} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{2} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{3}\label{4} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{3}\label{4} B
\par\noindent\begin{lrbox}{\mybox}
\verb*| \label{5} \label{6} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{5} \label{6} B
\makeatletter
\def\@esphack{%
\relax
\ifhmode
\spacefactor\@savsf
\ifdim\@savsk>\z@
\ifdim\lastskip=\z@
\nobreak
\hskip-\@savsk
\nobreak
\hskip\@savsk
% the total skip is zero and \lastskip is restored.
\fi
\ignorespaces
\fi
\fi
}%
\makeatother
\noindent\null\hrulefill\null
\par\noindent\begin{lrbox}{\mybox}
\verb*|A\label{a}B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A\label{a}B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{b} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{b} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{c}\label{d} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{c}\label{d} B
\par\noindent\begin{lrbox}{\mybox}
\verb*|A \label{e} \label{f} B|:
\end{lrbox}\hbox to 4.5cm{\usebox\mybox\hfil} A \label{e} \label{f} B
\end{document}
Does my modification of \@esphack have drawbacks?
Am I overlooking some caveat/something relevant?


\@bsphack..\@esphackclearer. – Mar 24 '19 at 23:29\lastskipso that one can have consecutive commands that don't produce visible output in a row? If by now you do something likeA \label{foo} \label{bar} B,\lastskipwill in any case be 0 after\label{foo}which affects the behavior of\label{bar}because with\label{bar}\@savskwill not be larger than\z@any more so that\ignorespaceswon't get carried out although it should be carried out? Is\nobreak\hskip-\@savsk\nobreak\hskip\@savskunsafe? – Mar 24 '19 at 23:40\labelinto the middle of a word? If so: What is the insertion of (zero-width-)glue good for in the context of not inhibiting hyphenation? – Mar 24 '19 at 23:56\index{..}were not hyphenated https://www.latex-project.org/cgi-bin/ltxbugs2html?category=LaTeX&responsible=anyone&state=anything&keyword=&pr=latex%2F3498&search= – David Carlisle Mar 25 '19 at 00:55\nobreak\hskip\z@skipto\nobreak\hskip-\@savsk\nobreak\hskip\@savskhave any drawbacks/pitfalls? (I edited my question for pointing out why I think that restoring\lastskipis necessary for the case of having consecutive commands whose definitions are wrapped in\@bsphack..\@esphack.) – Mar 25 '19 at 01:12\lastskipsees a positive skip at a place where there is no visible space, which might be bad in other contexts, I'd need to think about it. You could make a change suggestion at the new issue tracker at https://github.com/latex3/latex2e/issues so we don't lose the suggestion (you can reference this post) – David Carlisle Mar 25 '19 at 10:30\lastskipsees that positive skip (only?) in case\@savskwas positive due to a chain of consecutive\@bsphack..\@esphackthat was preceded by a positive skip/a visible space... (By the way: I implemented a similar\@bsphack/\@esphack-variant in my answer to Generating a Persistent and Unique IDs (for Requirements in a Specification) ) – Ulrich Diez Mar 25 '19 at 20:21\unskiprather than\lastskip, I added an example above (although not clearly bad example) – David Carlisle Mar 26 '19 at 08:10\nobreak\hskip-\@savsk\nobreak\hskip\@savskwould be\nobreak\hskip1spthat would keep a single glue node but be enough to trigger the "positive skip" case in a following space hack. – David Carlisle Mar 26 '19 at 12:04