9

The MWE below creates a \savebox within a group which results in several blank lines:

enter image description here

If I comment out the\begingroup and \endgroup I get the desired results:

enter image description here

My thinking was that adding the \global should have fixed this issue.

So, how do I create and define \savebox within a group and yet be able to use the outside of the group?

Notes:

  • While the MWE here does not need grouping my actual use case does, so I would really prefer to not have to eliminate the grouping.

Code:

\documentclass{article}
\usepackage{etoolbox}

\newcommand*{\MyLink}[2]{%
\begingroup
    \ifcsdef{MyBox #1-#2}{%
    }{%
        \typeout{*** Defined savebox for #1-#2}%
        \global\expandafter\newsavebox\csname MyBox #1-#2\endcsname%
        \global\expandafter\savebox\csname MyBox #1-#2\endcsname{#2: #1}%
    }%
    \expandafter\usebox\csname MyBox #1-#2\endcsname%
\endgroup
}%


\begin{document}
    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.apple.org}{A} 

    \MyLink{http://www.google.com}{G} 

    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.wikipedia.org}{W} 
\end{document}
  • why a box here (allocating a box every use is not usually recommended, even though etex means you have rather more than in classic tex) – David Carlisle Dec 16 '15 at 12:10
  • \global\savebox is definitely not going to work. – egreg Dec 16 '15 at 12:13
  • @DavidCarlisle: My actual use case is more involved, so the reason is for efficiency to save doing things thousands of times. – Peter Grill Dec 16 '15 at 12:13
  • @PeterGrill are you sure it's that much more efficient than a macro? – David Carlisle Dec 16 '15 at 12:18
  • @DavidCarlisle: Just did a small test. Using the solution you posted required less than 1/3 the elapsed time. – Peter Grill Dec 16 '15 at 12:33
5

I suspect that using a locally allocated box here is the wrong thing to do but to do it, just use the primitive commands to set the content:

\documentclass{article}
\usepackage{etoolbox}

\newcommand*{\MyLink}[2]{%
\begingroup
    \ifcsdef{MyBox #1-#2}{%
    }{%
        \typeout{*** Defined savebox for #1-#2}%
        \global\expandafter\newsavebox\csname MyBox #1-#2\endcsname%
        \global\expandafter\setbox\csname MyBox #1-#2\endcsname\hbox{{#2: #1}}%
    }%
    \expandafter\usebox\csname MyBox #1-#2\endcsname%
\endgroup
}%


\begin{document}
    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.apple.org}{A} 

    \MyLink{http://www.google.com}{G} 

    \MyLink{http://www.wikipedia.org}{W} 

    \MyLink{http://www.wikipedia.org}{W} 
\end{document}
7

Let's see what \global\savebox\foo does:

  1. \global expands \savebox so the input stream is

    \global\@ifnextchar ({\@savepicbox \foo}{\@ifnextchar [{\@savebox #1}{\sbox \foo}}
    
  2. \global expands \@ifnextchar, so the input stream is

    \global\let\reserved@d=( [...]
    

    (where [...] denote irrelevant tokens).

  3. \global is applied to \let.

Note that \global doesn't disappear until it finds a token it can apply to (\def, \let, a register address and so on; in general, an assignment).

This explains why you don't get errors, but also why you don't get a global setting for your box.

Doing \global\sbox\foo{tokens} would work, because the first expansion step triggered by \global is

\global\setbox\foo\hbox{\color@setgroup tokens\color@endgroup}

However, you may be using a stripped down example and perhaps you need the full force of \savebox, instead of \sbox, so you can use a temporary box register for the construction and then globally set the new register to be the same as the built box.

\documentclass{article}
\usepackage{etoolbox}

\newsavebox{\mylinkbox}
\newcommand*{\MyLink}[2]{%
\begingroup
    \ifcsdef{MyBox #1-#2}{%
    }{%
        \typeout{*** Defined savebox for #1-#2}%
        \global\expandafter\newsavebox\csname MyBox #1-#2\endcsname
        \savebox\mylinkbox{#2: #1}%
        \global\expandafter\setbox\csname MyBox #1-#2\endcsname\box\mylinkbox
    }%
    \expandafter\usebox\csname MyBox #1-#2\endcsname
\endgroup
}


\begin{document}
    \MyLink{http://www.wikipedia.org}{W}

    \MyLink{http://www.wikipedia.org}{W}

    \MyLink{http://www.apple.org}{A}

    \MyLink{http://www.google.com}{G}

    \MyLink{http://www.wikipedia.org}{W}

    \MyLink{http://www.wikipedia.org}{W}
\end{document}

enter image description here

  • Yes, example is heavily stripped down, but I am not sure I know what the "full force of \savebox" is. Is there a question here that explains what \savebox will do that \sbox can't? – Peter Grill Dec 16 '15 at 12:37
  • 1
    @PeterGrill \savebox accepts optional arguments the same way as \makebox does (after the mandatory first argument to \savebox, of course). So you can do \savebox{\foo}[2\width][l]{...}, for instance. – egreg Dec 16 '15 at 12:39
  • @PeterGrill it has optional arguments (for length etc, or picture mode) – David Carlisle Dec 16 '15 at 12:40

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.