9

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:

enter image description here

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]

1
  • 2
    Once you set \mylength, it won't change. Simple as that.
    – Werner
    Jul 10, 2013 at 15:31

3 Answers 3

4

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.

5
  • A big thank you for these suggestions. I didn't know there was a functional difference between the = and the \setlength syntaxes. Jul 10, 2013 at 18:38
  • \setlength adds a \relax that avoids the puzzling error I mentioned; rare, perhaps, but nasty when it happens.
    – egreg
    Jul 10, 2013 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? Jul 11, 2013 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, 2013 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. Jul 11, 2013 at 10:44
6

"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.

4
  • 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? Jul 10, 2013 at 15:39
  • @StevenB.Segletes just use \renewcommand\mylength{3ex} Jul 10, 2013 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? Jul 10, 2013 at 17:03
  • @StevenB.Segletes added a comment on your answer. (PS "David" is fine: I never use the formal form on the web:-) Jul 10, 2013 at 17:19
1

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}

enter image description here

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

4
  • 1
    \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. Jul 10, 2013 at 17:18
  • Why do you want to avoid the need to save \mylength as a string? Jul 10, 2013 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. Jul 10, 2013 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. Jul 10, 2013 at 18:23

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.