# A reusable newlength (no stop/break if length already defined)

Often I have separate .tikz files, which may contain stuff like \newlength{\mytmplen}; and given I'm not very original with names, the same statement ends up in multiple such files. Which turns out to be a problem, if I want to include all those files in a single .tex document -- then upon the second \newlength with the same argument, the compilation process would stop with:

! LaTeX Error: Command \mytmplen already defined.
Or name \end... illegal, see p.192 of the manual.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...

l.30 \newlength{\mytmplen}

?


So, I thought of devising a new newlength command, which would define the new length if it doesn't exist; but it would simply typeout a message, and go on if it does exist.

Obviously, I'd have to have a method to check if a command exists; and possibly a method to obtain the command name (e.g. mytmplen) from the command token (e.g. \mytmplen). So far, I found these posts relevant:

I will be posting my solution as answer below; of course, corrections or alternative methods for solving this would be much appreciated!

Your answer appears to work. A simpler method might consist of first \let-ting the length variable in question to \relax and then applying \newlength to it. Put differently, if you can't remember if a certain macro name has been used before to denote a length parameter (or anything else, really!) and if you're comfortable with (re)using it anyway, you can first \let it to \relax and then issue a \newlength directive.

\documentclass{article}
\begin{document}

\newlength\mytmplen
\setlength\mytmplen{10pt}
\the\mytmplen

\let\mytmplen\relax % let \mytmplen to \relax

\newlength\mytmplen % now it's safe to "re-issue" it as a length
\setlength\mytmplen{20pt}
\the\mytmplen

\end{document}


• Many thanks for that, @Mico - that is indeed a much simpler approach. Cheers! – sdaau Jun 15 '14 at 16:06
• @sdaau: Until the lengths registers run out. They are a limited resource. – Heiko Oberdiek Jun 15 '14 at 16:57
• @HeikoOberdiek - Is there a problem with running out of length registers if the same few ones get re-used over and over? – Mico Jun 15 '14 at 18:07
• @Mico: TeX has 256 at most, many of them already in use. With e-TeX 32768 are available, but package etex should be used to make them available. – Heiko Oberdiek Jun 15 '14 at 18:40
• @HeikoOberdiek - I guess my question is trying to get at a different issue: Is there a risk of running out of registers if the same macro name, say \mytmplen, is repeatedly first \let to \relax and then reissued as a length register via \newlength? – Mico Jun 15 '14 at 18:46

Here is a \providelength command that will define a new length if not already defined, but also checks whether the command passed as argument has been defined with \newlength, in order to issue an error message if you try to use, say, \providelength{\textit}.

\documentclass{article}

\makeatletter
\newcommand{\providelength}[1]{%
\@ifundefined{\expandafter\@gobble\string#1}
{% if #1 is undefined, do \newlength
\typeout{\string\providelength: making new length \string#1}%
\newlength{#1}%
}
{% else check whether #1 is actually a length
\sdaau@checkforlength{#1}%
}%
}

\newcommand{\sdaau@checkforlength}[1]{%
% get the first five characters from \meaning#1
\edef\sdaau@temp{\expandafter\sdaau@getfive\meaning#1TTTTT$}% % compare with the string "\skip" \ifx\sdaau@temp\sdaau@skipstring \typeout{\string\providelength: \string#1 already a length}% \else \@latex@error {\string#1 illegal in \string\providelength} {\string#1 is defined, but not with \string\newlength}% \fi } \def\sdaau@getfive#1#2#3#4#5#6${#1#2#3#4#5}
\edef\sdaau@skipstring{\string\skip}
\makeatother

\begin{document}

\providelength{\foo}
\providelength{\foo}
\providelength{\textit}

\stop


Here is the terminal output:

\providelength: making new length \foo

! LaTeX Error: \textit illegal in \providelength.

See the LaTeX manual or LaTeX Companion for explanation.
Type  H <return>  for immediate help.
...

l.31 \providelength{\textit}

? h
\textit is defined, but not with \newlength
?


A version with expl3, that avoids the trick for finding if the command is already a length.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\providelength}{m}
{
\cs_if_exist:NTF #1
{
\sdaau_providelength_check:N #1
}
{
\msg_info:nnx { providelength } { making } { \token_to_str:N #1 }
\newlength{#1}
}
}
\cs_new_protected:Nn \sdaau_providelength_check:N
{
\token_if_skip_register:NTF #1
{
\msg_info:nnx { providelength } { not-making } { \token_to_str:N #1 }
}
{
\msg_error:nnx { providelength } { defined } { \token_to_str:N #1 }
}
}
\msg_new:nnn { providelength } { making }
{
\token_to_str:N \providelength :~making~new~length~#1
}
\msg_new:nnn { providelength } { not-making }
{
}
\msg_new:nnnn { providelength } { defined }
{
#1~illegal~in~\token_to_str:N\providelength
}
{
#1~is~defined,~but~not~with~\token_to_str:N\newlength
}
\ExplSyntaxOff

\begin{document}

\providelength{\foo}
\providelength{\foo}
\providelength{\textit}

\stop


This is the excerpt from the log file

.................................................
. providelength info: "making"
.
. \providelength: making new length \foo
.................................................
\foo=\skip49
.................................................
. providelength info: "not-making"
.
. \providelength: \foo is already a length
.................................................

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! providelength error: "defined"
!
! \textit illegal in \providelength
!
! See the providelength documentation for further information.
!
! For immediate help type H <return>.
!...............................................

l.47 \providelength{\textit}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| \textit is defined, but not with \newlength
|...............................................

• Many thanks for that, @egreg - good to have that error checking facility; cheers! – sdaau Jun 15 '14 at 16:27

Ok, so first I looked up the definitions of \newlength and further using texdef:

$texdef -t latex \newlength \newlength: macro:#1->\@ifdefinable #1{\newskip #1}$ texdef -t latex \@ifdefinable

\@ifdefinable:
\long macro:#1#2->\edef \reserved@a {\expandafter \@gobble \string #1}\@ifundefined \reserved@a {\edef \reserved@b {\expandafter \@carcube \reserved@a xxx\@nil }\ifx \reserved@b \@qend \@notdefinable \else \ifx \reserved@a \@qrelax \@notdefinable \else #2\fi \fi }\@notdefinable

\$ texdef -t latex \@ifundefined

\@ifundefined:
macro:#1->\expandafter \ifx \csname #1\endcsname \relax \expandafter \@firstoftwo \else \expandafter \@secondoftwo \fi


So, apparently, one can get the command name from the command token, by using the stanza:

\edef\reserved@a{\expandafter\@gobble\string#1}


... and then the name in \reserved@a (without the backslash) can be used in macros that check for macro existence by command name.

Using those definitions, I've put together this code for a reusable newlength command, called \nnewlength:

\documentclass{article}

\makeatletter
\def\nnewlength#1{%
\edef\reserved@a{\expandafter\@gobble\string#1} %
\@ifundefined\reserved@a{%
\edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil} %
\ifx\reserved@b\@qend %
\typeout{  -- Not definable (1, \reserved@a): #1} %\@notdefinable %
\else %
\ifx\reserved@a\@qrelax %
\typeout{  -- Not definable (2, \reserved@a): #1} %\@notdefinable %
\else %
\typeout{  -- Making newskip: #1}
\newskip#1%
\fi %
\fi %
}%
{\typeout{  -- Not definable (E, \reserved@a): #1}} %\@notdefinable%
}
\makeatother

\typeout{1st pass...}
\nnewlength{\mytmplen}
\typeout{2nd pass...}
\nnewlength{\mytmplen}

\begin{document}

\typeout{3rd pass...}
\nnewlength{\mytmplen}

\end{document}


The output is:

This is pdfTeX, Version 3.1415926-2.3-1.40.12 (TeX Live 2011)
...
1st pass...
-- Making newskip: \mytmplen
2nd pass...
-- Not definable (E, mytmplen): \mytmplen
(./test.aux)
3rd pass...
-- Not definable (E, mytmplen): \mytmplen
(./test.aux) )
No pages of output.
Transcript written on test.log.