An unexpected outcome from PGF's \foreach

The following example from page 508 of PGF manual 2.40 gives me a result that I didn't expect.

\tikz[x=0.75cm,y=0.75cm]
\foreach \x [count=\xi] in {a,...,e}
\foreach \y [count=\yi] in {\x,...,e}
\node [draw, top color=white, bottom color=blue!50, minimum size=0.666cm]
at (\xi,-\yi) {$\mathstrut\x\y$}; I expected to see bc, bd, be, cd, ce, de.

The following gives the expected output:

\tikz[x=0.75cm,y=0.75cm]
\foreach \x [count=\xi] in {1,...,5}
\foreach \y [count=\yi] in {\x,...,5}
\node [draw, top color=white, bottom color=blue!50, minimum size=0.666cm]
at (\xi,-\yi) {$\mathstrut\x\y$}; I guess there is a bug in \foreach.

My own \newforeach gives using the code

\tikz[x=0.75cm,y=0.75cm]
\newforeach [count=\xi] \x in {a,...,e}
\newforeach [count=\yi,expand before fill] \y in {\x,...,e}
\node [draw, top color=white, bottom color=blue!50, minimum size=0.666cm]
at (\xi,-\yi) {$\mathstrut\x\y$};

This last output was what I expected from \foreach. Unfortunately, \newforeach isn't yet released because it is still being tested. You can ask for it and participate in testing it.

• Interesting. The only way I can get the behavior I expect is to use {a,b,c,d,e} instead of {a,...,e}. If you use {a,b,...,e} then the first two columns are correct, but not the third and fourth.. – Peter Grill Sep 16 '12 at 4:14

If you try

\foreach \x [count=\xi] in {1,...,5}
\foreach \y [count=\yi] in {\x,...,5}

then all is well: the problem is a bug in how the \foreach code handles alphabetic iteration. The relevant code is

\def\pgffor@makealphabetic#1{%
% Convert the number in the macro passed as #1 to a-z or A-Z.
\pgfutil@tempcnta=#1\relax%
\ifnum\pgfutil@tempcnta>95\relax%
\expandafter\def\expandafter#1\expandafter%
{\pgffor@alpha\pgfutil@tempcnta}%
\else%
\expandafter\def\expandafter#1\expandafter%
{\pgffor@Alpha\pgfutil@tempcnta}%
\fi%
}

Here, #1 is the temporary variable used to hold what will be printed/used as \x, \y, etc. It's a number, but is converted by the code above to a letter. However, the above does not do this correctly: all those \expandafters do not expand \pgfutil@tempcnta, which is what is actually needed. For me

\def\pgffor@makealphabetic#1{%
% Convert the number in the macro passed as #1 to a-z or A-Z.
\pgfutil@tempcnta=#1\relax%
\ifnum\pgfutil@tempcnta>95\relax%
\edef#1{\pgffor@alpha\pgfutil@tempcnta}%
\else%
\edef#1{\pgffor@Alpha\pgfutil@tempcnta}%
\fi%
}

fixes the issue as the letters are now 'baked in'.

(I've not traced it all through, but my guess is that with an explicit iteration list, there is no numerical part involved, hence you only see this when using ... notation.)

It's quite instructive to disable the conversion entirely here:

\documentclass{article}
\usepackage{tikz}
\makeatletter
\def\pgffor@makealphabetic#1{}
\makeatother
\begin{document}
\tikz[x=0.75cm,y=0.75cm]
\foreach \x [count=\xi] in {a,...,e}
\foreach \y [count=\yi] in {\x,...,e}
\node [draw, top color=white, bottom color=blue!50, minimum size=0.666cm]
at (\xi,-\yi) {$\mathstrut\x\y$};
\end{document}

as this shows up that \foreach deals with first case separately from all of the others. I'm not sure that's a great plan, as it leaves open the danger of variable behaviour.

• Reported as sourceforge.net/tracker/… – Joseph Wright Sep 16 '12 at 8:17
• @AhmedMusa Not needed here as the \edef is non-expandable, so TeX will do the assignment as expected: exactly the same as in the original definition. I do agree though it's 'better style' to terminate the assignment properly, either with \relax or a space. – Joseph Wright Sep 16 '12 at 12:55
• I think there should be \relax after -96 and -64, as \advance tries to expand \edef. I have added it. But your patch doesn't solve the problem. Did you actually try it? – Ahmed Musa Sep 16 '12 at 13:07
• @AhmedMusa I've just double-checked: yes, the change I have does work for me with your example. The change needs to be made after loading TikZ, of course, but other than that there is nothing special going on. – Joseph Wright Sep 16 '12 at 13:13
• I am sorry, it works. I added the patch with with @ having catcode 12. – Ahmed Musa Sep 16 '12 at 13:20