3

Why is \setlength ineffective inside a tabular environment? Here is an MWE:

\documentclass{article}
\newlength{\globallength}
\newlength{\locallength}
\begin{document}
\setlength{\globallength}{10pt}%
\begin{tabular}{l}
\setlength{\locallength}{10pt}%

\hspace*{10pt}. \\

\hspace*{\globallength}. \\

\hspace*{\locallength}. \\

\hspace*{0pt}. \\

\end{tabular}
\end{document}

While the first two dots are well-aligned, the third one is different and behaves as if \locallength were 0pt. Why is that, and what can I do? I want to use \setwidth inside the tabular environment, so setting the length outside of the environment is not really an option.

13
  • 2
    Your length registers are locally set, i.e. in a group. A table cell is a group! That's why you need a \global\setlength{....}
    – user31729
    Mar 25, 2016 at 13:16
  • @ChristianHupfer: please post answer. Or is this question a duplicate?
    – GuM
    Mar 25, 2016 at 13:21
  • 1
    @ChristianHupfer \global\setlength will not work with package calc. Mar 25, 2016 at 13:22
  • 3
    @ChristianHupfer The other version \setlength{\global\locallength} will work with calc, but it won't for \addtolength. A way independent from the implementation of \setlength: \setlength{\locallength}{...}\global\locallength=\locallength. Mar 25, 2016 at 13:35
  • 1
    The burden of a non-native speaker... I'll try again: Before asking this question, I was sure the smallest entity in a table that would form a group is the table itself, not a row (this is what my last two comments are about), and certainly not a cell. I know now that a cell is a group, which does not mean that a row is a group, but which means that there are groups "at or below the level of a single table row".
    – bers
    Mar 25, 2016 at 14:01

2 Answers 2

3

Alignment cells are processed inside an implicit group, so local assignments to variables are undone when the group ends.

The kernel definition of \setlength is

% latex.ltx, line 2181:
\def\setlength#1#2{#1 #2\relax}

which is why \global\setlength seems to work. On the other hand, the definition of \settowidth is

% latex.ltx, line 2187:
\def\settowidth {\@settodim\wd}

and the definition of \@settodim is

% latex.ltx, line 2183:
\def\@settodim#1#2#3{\setbox\@tempboxa\hbox{{#3}}#2#1\@tempboxa
       \setbox\@tempboxa\box\voidb@x}

Thus \global\settowidth{\locallength}{abc} would become

\global\setbox\@tempboxa\hbox{{abc}}\locallength\wd\@tempboxa\setbox\@tempboxa\box\voidb@x

which of course is ineffective in making a global assignment to \locallength.

Yes, \settowidth{\global\locallength}{abc} would work, but it's just by chance.

There is no support in LaTeX for global dimension/skip assignments and you should rely on lower level commands. So a safer way is to define new commands:

\makeatletter
\newlength\local@length@for@global
\newcommand\gsetlength[2]{%
  \setlength{\local@length@for@global}{#2}%
  \global#1\local@length@for@global
}
\newcommand{\gsettowidth}[2]{%
  \settowidth{\local@length@for@global}{#2}%
  \global#1\local@length@for@global
}
\makeatother

and similarly for \gsettoheight and \gsettodepth if needed.

This will work even if calc is loaded and does not exploit any particular implementation of the “local” commands.

0

Both \global\setlength{\locallength}{10pt} and \setlength{\global\locallength}{10pt} seem to work, but I have no idea why that would be required.

https://tex.stackexchange.com/a/210598/30810 made me try it, and @ChristianHupfer's comment explains, why.

In my longer document, \global\settowidth{...} did not work; \settowidth{\global...} did.

You must log in to answer this question.

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