Skip to content

engine: \global in front of a LaTeX length command - #98

Merged
tannevaled merged 1 commit into
mainfrom
global-setlength
Aug 27, 2026
Merged

engine: \global in front of a LaTeX length command#98
tannevaled merged 1 commit into
mainfrom
global-setlength

Conversation

@tannevaled

Copy link
Copy Markdown
Contributor

\global\setlength\xx{5pt} inside a group was a local assignment: it took
effect inside the group and was undone on the way out, in silence.
\global\xx=5pt and \global\advance\xx by4pt both worked, which is what kept
the hole out of sight.

Why TeX does not have it

tex.web §1211: a prefix applies to the assignment it finds after expanding
what follows — it takes "the next non-blank non-relax non-call token", so a
macro is expanded away. And \setlength is a macro there:

\def\setlength#1#2{#1 #2\relax}      % ltlength.dtx

so \global reaches the register assignment by itself. Here \setlength is a
primitive, which getXToken does not expand, and doGlobal's switch had no case
for it — the default branch put the token back and ran it locally.

The machinery was already in place: assignLength takes a global flag that
nothing ever passed as true. \setlength, \addtolength, \settowidth,
\settoheight and \settodepth now receive the prefix, so it works for a
\newlength register and for one of the engine's dimension parameters
(\textwidth is \let to \hsize — a different path, same rule).

Measured

beamer (200 talks) arXiv (200 papers)
documents lost 0 0
outputs changed 0 0
page count 1061 → 1061 3563 → 3563

Both corpora are inert, which is what a fix this narrow should look like: no
document in either set exercises \global\setlength in a way that reaches the
page. The behaviour is pinned by tests instead.

Both baselines were re-run with the current main binary rather than reused from
earlier today — main moved in between (#95 changed glyph widths by ~1.7%), and a
stale baseline would have credited this change with someone else's deltas.

A correction

One test case of mine was wrong before the engine was: I asserted \the\xx after
setting \textwidth. Removed — the parameter path has its own test.

\global\setlength\xx{5pt} inside a group was a LOCAL assignment: it took effect
inside the group and was undone on the way out, in silence. \global\xx=5pt and
\global\advance\xx by4pt both worked, which is what kept the hole out of sight.

In TeX a prefix applies to the assignment it finds after EXPANDING what follows —
tex.web §1211 takes "the next non-blank non-relax NON-CALL token", so a macro is
expanded away. \setlength is a macro there (ltlength.dtx: \def\setlength#1#2{#1
#2\relax}), so \global reaches the register assignment by itself. Here it is a
primitive, which getXToken does not expand, and doGlobal's switch had no case for
it: the default branch put the token back and ran it locally.

The machinery was already in place — assignLength takes a global flag that nothing
ever passed as true. \setlength, \addtolength, \settowidth, \settoheight and
\settodepth now receive the prefix, so they reach both a \newlength register and
one of the engine's dimension parameters (\textwidth is \let to \hsize, a
different path, same rule).

Measured over 200 real beamer talks: 0 documents lost, 0 outputs changed, page
count identical — the change is inert on that corpus, which is what a fix this
narrow should look like.

One test case of mine was wrong before the engine was: I asserted \the\xx after
setting \textwidth. Removed; the parameter path has its own test.
@tannevaled
tannevaled merged commit 7f898c5 into main Aug 27, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant