3

I am setting a custom length to equal the value of \leftmargin inside an enumitem list. Once I exit the list though the value disappears and my custom length reverts to zero.

I have shown the behaviour below in a MWE:

\documentclass{article}
\usepackage{enumitem}
\newlength\Mylen
\setlength{\Mylen}{0em}

\begin{document}
Hello world. Value of Mylen is \the\Mylen.
\begin{enumerate}[leftmargin=40pt,labelsep=1em, label={P\arabic*}]
\item Test line 1.
\item Test line 2.
\item Test line 3. The value of leftmargin is \the\leftmargin. Value of Mylen is \the\Mylen. \addtolength{\Mylen}{\leftmargin} Value of Mylen is now the sum of leftmargin and original value = \the\Mylen.
\end{enumerate}
 Value of Mylen is \the\Mylen ~again!

\end{document}

I cannot understand why this happens. Any help?

2

Length adjustments respect the scope they're in, as is demonstrated by the minimal example below. So, setting or changing it inside a group will revert it back to its original definition/setting before the group. You could use \global<len>=<len> to make the change global, thereby avoiding the scope limitation:

\documentclass{article}

\begin{document}

\newlength{\mylen}
\setlength{\mylen}{40pt}\the\mylen% 40.0pt

\begingroup
\setlength{\mylen}{50pt}\the\mylen% 50.0pt
% https://tex.stackexchange.com/a/119738/5764
%\global\mylen=\mylen% Make above assignment global
\endgroup

\the\mylen% 40.0pt, or 50.0pt when using \global

\end{document}

Another option would be to use global definitions rather than lengths to keep the length:

\documentclass{article}

\begin{document}

\newlength{\mylen}
\setlength{\mylen}{40pt}\the\mylen% 40.0pt

\begingroup
\setlength{\mylen}{50pt}\the\mylen% 50.0pt
\xdef\mylenval{\the\mylen}% 50.0pt
\endgroup

\the\mylen% 40.0pt

\mylenval% 50.0pt

\setlength{\mylen}{\mylenval}\the\mylen% 50.0pt

\end{document}

While \mylenval is a (global) macro, it contains the length at the time of definition that you can use in the setting of other lengths, as in \setlength{\mylen}{\mylenval}.

2

Assignments like \setlength, \addtolength, \settowidth, \settoheight and \settodepth are local, in the sense that they are only valid in the group they are issued; an environment constitutes a group, like alignment cells and boxes (\mbox, \makebox, \fbox and so on).

If you need global versions of these commands, it's not really difficult to make versions that also work with calc and don't require using \global in the wild.

\documentclass{article}
\usepackage{enumitem}
\usepackage{calc} % just for testing

\makeatletter
\newlength{\g@temp@len}

\newcommand{\gsetlength}[2]{%
  \setlength{\g@temp@len}{#2}%
  \global#1\g@temp@len
}
\newcommand{\gaddtolength}[2]{%
  \addtolength{\g@temp@len}{#2}%
  \global#1\g@temp@len
}
\newcommand{\gsettowidth}[2]{%
  \g@settodim\wd{#1}{#2}%
}
\newcommand{\gsettoheight}[2]{%
  \g@settodim\ht{#1}{#2}%
}
\newcommand{\gsettodepth}[2]{%
  \g@settodim\dp{#1}{#2}%
}
\newcommand{\g@settodim}[3]{%
  \@settodim#1\g@temp@len{#3}%
  \global#2\g@temp@len
}
\makeatother

\newlength\Mylen

\begin{document}

Hello world. Value of Mylen is \the\Mylen.
\begin{enumerate}[leftmargin=40pt,labelsep=1em, label={P\arabic*}]
\item Test line 1.
\item Test line 2.
\item Test line 3. The value of leftmargin is \the\leftmargin. 
      Value of Mylen is \the\Mylen. \gaddtolength{\Mylen}{\leftmargin} 
      Value of Mylen is now the sum of leftmargin and original value = \the\Mylen.
\end{enumerate}
 Value of Mylen is \the\Mylen{} as expected!

\mbox{\gsetlength{\Mylen}{3pt}X}\the\Mylen

\mbox{\gsettowidth{\Mylen}{\widthof{XX}}}\the\Mylen

\mbox{\gaddtolength{\Mylen}{2pt}}\the\Mylen

\end{document}

enter image description here

It's better to avoid local and global assignments to the same variable.

1

Unlike LaTeX counters length registers are group-safe, i.e. changing their values inside a group (like \begin{enumerate}...\end{enumerate}) does not survive the exit of the group, i.e. the change is not persistent unless \global\addtolength is used here.

Since the definition of \addtolength is (see latex.ltx)

\def\addtolength#1#2{\advance#1 #2\relax}

\global\addtolength... is the same as a \global\advance.... here

However, since calc changes the definitions of \addtolength, I provide another version:

\documentclass{article}
\usepackage{enumitem}
\usepackage{calc}%

\newcommand{\increaselength}[2]{%
  \global\advance#1 by #2\relax
}%
\newlength\Mylen
\setlength{\Mylen}{0em}

\begin{document}
Hello world. Value of Mylen is \the\Mylen.
\begin{enumerate}[leftmargin=40pt,labelsep=1em, label={P\arabic*}]
\item Test line 1.
\item Test line 2.
\item Test line 3. The value of leftmargin is \the\leftmargin. Value of Mylen is \the\Mylen. \global\advance\Mylen by \leftmargin. Value of Mylen is now the sum of leftmargin and original value = \the\Mylen.
\item Test line 3. The value of leftmargin is \the\leftmargin. Value of Mylen is \the\Mylen. \increaselength{\Mylen}{10pt} Value of Mylen is now the sum of leftmargin and original value = \the\Mylen.

\end{enumerate}
 Value of Mylen is \the\Mylen ~again!

\end{document}

enter image description here

  • No, please, not \global\addtolength! Try it with calc. – egreg Jul 6 '16 at 18:14
  • Sorry I should have said this is an extract of much more complex document, I believe I have some package or other which, like calc, prevents this method working. Is it nonetheless possible to save the value of leftmargin computed by enumitem for later use? – demodave Jul 6 '16 at 18:17
  • @egreg: Alright, calc does changes to this :-( – user31729 Jul 6 '16 at 18:17
  • @demodave: Yes, you should have said this :-(, but I changed it – user31729 Jul 6 '16 at 18:20
  • @Christian Hupfer, Thanks for the lightning answer though! – demodave Jul 6 '16 at 18:24

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.