Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have made my own lists. I want to refer to them outside the lists. If I do a calculation using counters at a certain point in my list hierarchy, say \alph{listcounter}, how do I freeze that result at the point I'm calculating it so that when I refer to it later it has the original calculated value. LaTeX delays the calculation of \alph{listcounter} until I eventually put it onto a page at which point the listcounter value is inappropriate.

I am determined not to use a readymade list package and really need a solution to this problem for general use. What I'm after is a way to freeze the result into a variable, and not the calculation that produces it.

I can freeze strings like this in a file and that's overkill I think, but it shows the string can be frozen. The string I'm using has no formatting as that was creating all kinds of bother as well. I realise that generalising this routine for multiple references is going to be a nightmare all its own but the following code is deliberately trivial to demonstrate the problem.

What is the usual way of saving a snapshot of the value of an expression?

I'm a newbie here but only a seminewbie with LaTeX. I've had a great deal of help from this site in the past. Much appreciated.

\documentclass[12pt]{article}

\usepackage{amsmath}

\newcommand{\makeref}{Q\arabic{numqpoints}(\alph{numapoints})}

\def\qmg{1.4em}\def\amg{1.4em}

\newcounter{listnest}\setcounter{listnest}{1}
\newcounter{reftype}

\newcommand{\setlistbody}[1]
{
\setlength\parsep{3pt}
\setlength\labelsep{3pt}
\setlength\labelwidth{1.6em}
\ifnum\value{listnest}=1
    \setlength\leftmargin{0pt}
\else
    \setlength\leftmargin{\ifcase#1\or\qmg\or\amg\fi}
\fi
\setcounter{reftype}{#1}
\stepcounter{listnest}
}

\newcounter{numqpoints}
\newenvironment{qpoints}
%
{\begin{list}
{{\bf Q}\,\arabic{numqpoints}}
{\usecounter{numqpoints}\setlistbody1}
}
{\end{list}
    \addtocounter{listnest}{-1}
    \setcounter{numqpoints}{0}
}

\newcounter{numapoints}
\newenvironment{apoints}
%
{\begin{list}
    {(\alph{numapoints})}
    {\usecounter{numapoints}\setlistbody2}
}
{\end{list}
    \addtocounter{listnest}{-1}
    \setcounter{numapoints}{0}
}

\newwrite\tempfile
\newcommand{\freezestring}[1]
{
\immediate\openout\tempfile=lists.tex
\immediate\write\tempfile{#1}
\immediate\closeout\tempfile
\global\def\savestring{\input{lists}}
}

\begin{document}
%
\begin{qpoints}
\item One
\item Two
    \begin{apoints}
    \item AAA
    \item \freezestring{\makeref} \global\def\varstring{\makeref}
    BBB Here is what I want: \savestring
    \end{apoints}
\end{qpoints}
%
\par Here is what I get with a variable: \varstring
%
\par Here is what I get with a file: \savestring
%
\end{document}

Addendum 1: Okay, now that seems to be solved in a basic way, I'll move this to the next level of complication. I need flexibility in putting these strings together as I want the list levels used in various combinations. I know how to keep track of which level is which so I'll just focus on the next reference string problem. Using loops to construct a string breaks the \xdef solutions as provided. The following loop works on its own but crashes inside the \xdef.

My loop code follows. Am I asking too much now?

\newcounter{nexttype}
\newcommand{\printref}
{
\setcounter{nexttype}{1}%
\loop%
\ifcase\value{nexttype}%
\or Q\arabic{numqpoints}%
\or (\alph{numapoints})%
\fi%
\ifnum\value{listnest}>\value{nexttype}%
\stepcounter{nexttype}%
\repeat%
}

Addendum2: Okay, I'm clearly not asking too much because I solved this myself. It dawned on me that I could just append stuff to the original on the fly variable so nothing nasty had to be passed to it directly.

\newcommand{\makerefvar}[2]{\expandafter\xdef\csname Wiz#1\endcsname{#2}}
\newcommand{\getref}[1]{\csname Wiz#1\endcsname}

\newcounter{thistype}
\newcommand{\makeref}[1]
{
\makerefvar{#1}{}\getref{#1}
\setcounter{thistype}{1}%
\loop%
\ifcase\value{thistype}%
\or \makerefvar{#1}{{\getref{#1}Q\arabic{numqpoints}}}%
\or \makerefvar{#1}{\getref{#1}(\alph{numapoints})}%
\or \makerefvar{#1}{\getref{#1}\roman{numrpoints}}%
\fi%
\ifnum\value{listnest}>\value{thistype}%
\stepcounter{thistype}%
\repeat%
}
share|improve this question
    
@egreg - Your original solution worked with simple expressions that include things like '\alph{counter}' but when using '\loop .. \if .. \repeat' it breaks. Thanks for your help so far, is this further complication too much? –  Geoff Pointer Sep 23 '13 at 3:52
    
@egreg - I've solved this latter complication. See my original post Addendum 2. I knew there had to be a way and I don't normally hang about waiting for other people to solves things for me. Thanks for your input it pushed me in the right direction. BTW, I was already using code for constructing variables with common prefixes, which I found on this website of course. (I'm also going to have to watch not hitting the return key when it's only comment.) - Cheers. –  Geoff Pointer Sep 23 '13 at 5:15
    
I found it difficult to chose an answer. Joseph Wright's answer was fundamentally the same as egreg's and the main point of the problem. Ultimately a good student can code the details. None the less, egreg serendipitously incorporated command family construction, which I'd been working on already, so the extra coding in his answer tied in nicely. Thanks to Joseph for highlighting the \protected aspect and he did give a more detailed explanation of why \xdef is necessary. Of course, a good student will look up the details once pointed in the right direction. Thanks to both of you. –  Geoff Pointer Sep 23 '13 at 9:31

2 Answers 2

up vote 4 down vote accepted

If you need the reference always later than having set it, you can \xdef a suitable control sequence.

\documentclass[12pt]{article}

\usepackage{amsmath}

\newcommand{\makeref}[1]{%
  \expandafter\xdef\csname geoff@#1\endcsname{%
    Q\arabic{numqpoints}(\alph{numapoints})%
  }%
}
\newcommand{\getref}[1]{%
  \csname geoff@#1\endcsname
}

\def\qmg{1.4em}\def\amg{1.4em}

\newcounter{listnest}\setcounter{listnest}{1}
\newcounter{reftype}

\newcommand{\setlistbody}[1]{%
  \setlength\parsep{3pt}%
  \setlength\labelsep{3pt}%
  \setlength\labelwidth{1.6em}
  \ifnum\value{listnest}=1
    \setlength\leftmargin{0pt}%
  \else
    \setlength\leftmargin{\ifcase#1\or\qmg\or\amg\fi}%
  \fi
  \setcounter{reftype}{#1}%
  \stepcounter{listnest}
}

\newcounter{numqpoints}
\newenvironment{qpoints}
  {\begin{list}
   {\textbf{Q}\,\arabic{numqpoints}}
   {\usecounter{numqpoints}\setlistbody1}}
  {\end{list}%
   \addtocounter{listnest}{-1}%
   \setcounter{numqpoints}{0}}

\newcounter{numapoints}
\newenvironment{apoints}
  {\begin{list}
   {(\alph{numapoints})}
   {\usecounter{numapoints}\setlistbody2}}
  {\end{list}%
   \addtocounter{listnest}{-1}%
   \setcounter{numapoints}{0}}

\begin{document}
%
\begin{qpoints}
\item One
\item Two
    \begin{apoints}
    \item AAA
    \item \makeref{BBB}
    BBB Here is what I want: \getref{BBB}
    \end{apoints}
\end{qpoints}

Here is the reference: \getref{BBB}
%
\end{document}

A different solution uses the \label-\ref mechanism.

\documentclass[12pt]{article}

\usepackage{amsmath}

\makeatletter
\newcommand{\makeref}[1]{%
  \edef\@currentlabel{Q\arabic{numqpoints}(\alph{numapoints})}%
  \label{geoff@#1}
}
\makeatother
\newcommand{\getref}[1]{\ref{geoff@#1}}

\def\qmg{1.4em}\def\amg{1.4em}

\newcounter{listnest}\setcounter{listnest}{1}
\newcounter{reftype}

\newcommand{\setlistbody}[1]{%
  \setlength\parsep{3pt}%
  \setlength\labelsep{3pt}%
  \setlength\labelwidth{1.6em}
  \ifnum\value{listnest}=1
    \setlength\leftmargin{0pt}%
  \else
    \setlength\leftmargin{\ifcase#1\or\qmg\or\amg\fi}%
  \fi
  \setcounter{reftype}{#1}%
  \stepcounter{listnest}
}

\newcounter{numqpoints}
\newenvironment{qpoints}
  {\begin{list}
   {\textbf{Q}\,\arabic{numqpoints}}
   {\usecounter{numqpoints}\setlistbody1}}
  {\end{list}%
   \addtocounter{listnest}{-1}%
   \setcounter{numqpoints}{0}}

\newcounter{numapoints}
\newenvironment{apoints}
  {\begin{list}
   {(\alph{numapoints})}
   {\usecounter{numapoints}\setlistbody2}}
  {\end{list}%
   \addtocounter{listnest}{-1}%
   \setcounter{numapoints}{0}}

\begin{document}
%
\begin{qpoints}
\item One
\item Two
    \begin{apoints}
    \item AAA
    \item \makeref{BBB}
    BBB Here is what I want: \getref{BBB}
    \end{apoints}
\end{qpoints}

Here is the reference: \getref{BBB}
%
\end{document}

This is the output in both cases. The second strategy seems the best, although it requires two LaTeX runs to stabilize.

enter image description here

share|improve this answer

You have a not uncommon misunderstanding going on here: \global\def\varstring{\makeref} defines \varstring to expand to \makeref not the value of \makeref. So when you use \varstring you are inserting \makeref, which then expands to

Q\arabic{numqpoints}(\alph{numapoints})

and so you get whatever the current value of the the counters is.

Instead, you need to use an expanded definition, so \varstring contains the current appearance of \makeref. We could use the TeX \xdef primitive for this, but in general you should not use TeX primitive expansion with LaTeX material. Instead, I would use \protected@xdef:

\begin{qpoints}
\item One
\item Two
    \begin{apoints}
    \item AAA
    \item \freezestring{\makeref}
     \makeatletter\protected@xdef\varstring{\makeref}\makeatother
    \end{apoints}
\end{qpoints}

That works because LaTeX then keeps expanding \makeref until only non-expandable things (numbers, letters, ...) remain.

I would probably consider saving only the current values of the counters, as you may want to do stuff other than use the formatted version. However, that is down to you!


Note on the difference between \xdef and \protected@xdef. First, these are global versions of \edef and \protected@edef, respectively, so the comments here apply to both cases. The TeX primitives \edef/\xdef keep expanding everything inside a definition until they reach 'unexpandable' material. At the primitive level, that makes sense but with LaTeX commands can go wrong. Not everything 'makes sense' fully expanded, and indeed can lead to errors as in particular assignments are not carried out during expansion. As such, LaTeX provides \protected@edef/\protected@xdef, which are set up such that various LaTeX commands are 'made safe' and don't get expanded. Normally, it's regarded as best to use the \protected@edef/\protected@xdef for expanding LaTeX material, with \edef/\xdef really only safe if you are in 'full control' of the input.

In the current case, the display counters could be altered from the standard, expandable, \alph, so I'm being cautious.

share|improve this answer
    
To be fair I don't have this misunderstanding. I explained in my original question that I understood the delayed evaluation thing. I just didn't have the solution, although I'd found a hack that clarified it for me. Your solution worked when I tried it. Both you and egreg have demonstrated an application of \xdef, but why have you used \protected as well? –  Geoff Pointer Sep 23 '13 at 3:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.