# Defining a Length that Scales with Fontsize Changes

I noticed a behavior regarding lengths under fonstsize changes, which I'm hoping there is a way to circumvent. Consider this MWE:

\documentclass{article}
\begin{document}

\newlength\mylength
\mylength=\baselineskip
\def\stringmylength{\the\baselineskip}

mylength~~~  baselineskip~~~ stringmylength\\

\the\mylength~~~~~~~~\the\baselineskip~~~~~~~~~~~~~\stringmylength\\

\Large
\the\mylength~~~\the\baselineskip~~~~~~~\stringmylength\\

\end{document}


with this output:

When I define a length in a scalable unit (here, as \baselineskip, though the same behavior occurs if I define \mylength as 2.7871ex), I would hope that, upon changing the fontsize, it would scale. But \mylength does not. I seem to recall reading somewhere that lengths are converted to some internal LaTeX unit, which would explain, perhaps, why a length, once specified, doesn't scale with fontsize.

Yet, it is clear that certain lengths do scale, such as \baselineskip, as given in my example.

Also, I could "work around" the problem by storing the length not as a length, but as a string (\stringmylength in my example), though that seems crass to me.

Is there a way to define a LaTeX length which will scale with fontsize changes?

If not, what is the prescribed way of manually modifying lengths to conform to fontsize changes?

[EDIT: As mentioned in a comment to David, and picked up on by egreg, this question concerns the formulation of lengths in the stackengine package]

-
Once you set \mylength, it won't change. Simple as that. – Werner Jul 10 '13 at 15:31

Recommending, in your package documentation, a syntax such as \Sstackgap=0.7ex is disputable; the standard LaTeX syntax uses \setlength and since \Sstackgap is a skip register (since you define it with \newlength), this opens the way to weird errors; a user typing

\Sstackgap=0.3ex Plus other things


will be puzzled with a strange error message Missing number treated as 0. Do you see why?

If you want this length to be expressed in the font based units em or ex, respecting the current font, you must treat it as a macro:

\newcommand{\setstackgap}[2]{%
\@namedef{#1stackgap}{#2}%
}


where #1 is either L or S (add an error checking routine). Then you can say

\newcommand\stackgap{%
\@nameuse{\if S\stacktype S\else L\fi stackgap}\relax
}


and the user can say

\setstackgap{S}{.7ex}
\setstackgap{L}{.3em}


or whatever. Alternatively, define a \stackengineset macro:

\newcommand{\stackengineset}[2]{\def#1{#2}}


so users can type

\stackengineset{\Sstackgap}{0.7ex}


Note that in both ways a fixed length can be specified as well.

You could use a syntax such as \Sstackgap=0.7ex, by doing

\def\Sstackgap{\afterassignment\@foo\skip@}
\def\@foo{\edef\@Sstackgap{\the\skip@}}


and modifying \stackgap to use \@Sstackgap instead of \the\Sstackgap; similarly for \Lstackgap. But I can't recommend this way of doing things, contrary to the standard LaTeX syntax.

-
A big thank you for these suggestions. I didn't know there was a functional difference between the = and the \setlength syntaxes. – Steven B. Segletes Jul 10 '13 at 18:38
\setlength adds a \relax that avoids the puzzling error I mentioned; rare, perhaps, but nasty when it happens. – egreg Jul 10 '13 at 19:16
I have a subjective question regarding the revised package, and I value your opinion. I will have an [oldsyntax] option for backward compatibility. But should I make it so that use of old syntax (without the option) produces a compiler error (streamlined code, but perhaps confusing to the user) or do I perform the error checking for every stack (slowing down the execution) to make it compile but, on error, print in the user document that the syntax is obsolete and needs to be revised? – Steven B. Segletes Jul 11 '13 at 10:19
@StevenB.Segletes This is a tough decision. However, the package is recent, so it shouldn't have a very large user base yet. I'd go for the compiler error. – egreg Jul 11 '13 at 10:37
Regarding using old syntax in a revised package, \setlength... will produce a compiler error, whereas \Sstackgap=3ex will produce something like "3pt=3ex" in the user's output, which may seem stranger. Perhaps that is what documentation is for. If consulted, it provides the remedy immediately. Also, once updated, I will revise all my posts here on stackengine that are affected. – Steven B. Segletes Jul 11 '13 at 10:44

"crass" it may be but that's what you should do: store it as a macro.

\baselineskip does not change automatically, the baseline for each font size is stored in macro definitions and baseline length is set within the \selectfont macro each time the font changes.

-
Since \mylength will not (as much as I would like it to) be reset via \selectfont, are you suggesting that rather than letting a user of my code specify \mylength=3ex, that instead he should say \setmylength{3ex}, where \setmylength is a new macro of mine which will store 3ex as a string, to be used as needed? Or is modifying \selectfont an option, or not recommended? – Steven B. Segletes Jul 10 '13 at 15:39
@StevenB.Segletes just use \renewcommand\mylength{3ex} – David Carlisle Jul 10 '13 at 15:50
Dr. Carlisle, could you please check out my posted answer on this page, to see if what I did will work or not? – Steven B. Segletes Jul 10 '13 at 17:03
@StevenB.Segletes added a comment on your answer. (PS "David" is fine: I never use the formal form on the web:-) – David Carlisle Jul 10 '13 at 17:19

Based on David Carlisle's answer that certain "scalable" length changes, for lengths like \baselineskip, occur within \selectfont, I was wondering if there anything wrong with this approach which modifies \selectfont? Will it break something else? Will it not behave as I think/hope it will?

It avoids the need to save \mylength as a string.

\documentclass{article}
\usepackage{fp}
\newcount\oldsize
\newcount\newsize
\newlength\mylength
\let\svselectfont\selectfont

\def\selectfont{%
\oldsize=\baselineskip\relax%
\svselectfont%
\newsize=\baselineskip\relax%
\FPdiv\result{\the\newsize}{\the\oldsize}%
\setlength\mylength{\result\mylength}%
}

\begin{document}

\mylength=\baselineskip
\def\stringmylength{\the\baselineskip}

\baselineskip=\the\baselineskip

mylength~~~  baselineskip~~~ stringmylength\\

\the\mylength~~~~~~~~\the\baselineskip~~~~~~~~~~~~~\stringmylength\\

\Large
\the\mylength~~~\the\baselineskip~~~~~~~\stringmylength\\

\end{document}


Hat tip to egreg (via percusse) for the counter=length trick at Dividing dimensions to get a count

-
\selectfont is a robust command and this makes it fragile so you should use \DeclareRobustCommand (or etex \protected\def) Patching a core latex command always has potential failures especially if someone else patches the same thing, that is the main cause of package order loading conflicts. If you were to do this I would use \f@size rather than \baselineskip as the multiplier (that is the font size rather than the baseline) that is more consistent with using em. That is do you want your length to get bigger if someone uses \fontsize{10}{20}\selectfont ie double spaced. – David Carlisle Jul 10 '13 at 17:18
Why do you want to avoid the need to save \mylength as a string? – David Carlisle Jul 10 '13 at 17:20
@DavidCarlisle As to "Why do you want to avoid the need to save \mylength as a string?" it involves an upgrade to an existing package of mine (stackengine) where the user is already told he can say \Sstackgap=1ex (i.e., specify the length directly). I already warn the user in the documentation that if he changes fontsize, he needs to respecify the stackgap size (which is what you suggested with the \renewcommand...), but I thought it would just be nice to automate it for him. But obviously not, if it would break other things. In retrospect, I should have gone the macro route to start. – Steven B. Segletes Jul 10 '13 at 17:31
@DavidCarlisle I realize that my approach above approach is not good either. If the user wanted his length in non-scalable units (e.g., pts), then this approach would scale it for him against his wishes. So, the string macro approach is really the only one that makes sense, I'm coming to realize. – Steven B. Segletes Jul 10 '13 at 18:23