7

I had a look at TeX-FAQ on Non-letters in macro names and tried to implement the approach #2. It looks like I'm missing something. When trying to refer later to the new commands the result is not what I expected.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}

\newcommand{\DefineNode}[2] { \expandafter\newcommand\csname node-#1\endcsname{#2} } \newcommand{\GetNode}[1]{\csname node-#1\endcsname}

\begin{tikzpicture} \def \intra {1} \def \inter {3}

% Calculate values \foreach \x [count=\xi from 0] in {a,...,c} { \pgfmathsetmacro\tmpi{\xi * \inter} \DefineNode{n\x.0}{\tmpi}

\pgfmathsetmacro\tmpii{\xi * \inter + \intra}
\DefineNode{n\x.1}{\tmpii}

\message{\GetNode{n\x.0} ^^J}
\message{\GetNode{n\x.1} ^^J}

}

% Doing something with them later \foreach \x in {a,...,c} { \message{\GetNode{n\x.0} ^^J} \message{\GetNode{n\x.1} ^^J} } \end{tikzpicture}

\end{document}

The result is:

0.0
1.0
3.0
4.0
6.0
7.0
\node-na.0
\node-na.1
\node-nb.0
\node-nb.1
\node-nc.0
\node-nc.1

Instead of repeating numbers twice.

EDIT: Solved the group issue by forcing names to be globals.

\newcommand{\DefineNode}[2]
{
  \globaldefs=1\relax
  \expandafter\newcommand\csname node-#1\endcsname{#2}
}

Result currently:

0.0
1.0
3.0
4.0
6.0
7.0
6.0
7.0
6.0
7.0
6.0
7.0

Instead of repeating first 6 lines, now 6.0 and 7.0 are repeated. This is due to using only two macros \tmpi and \tmpii. How to solve this?

David Carlisle
  • 757,742
karu
  • 474
  • 1
    Maybe TikZ \foreach defines a group? In this case the definition would be local to the body of \foreach. – Stephan Lehmke Jul 09 '14 at 14:12
  • Welcome to TeX.SX! You can have a look at our starter guide to familiarize yourself further with our format. – Stephan Lehmke Jul 09 '14 at 14:13
  • According to http://tex.stackexchange.com/a/75152/56821 TikZ \foreach defines two groups. Edited the question to solve the group issue. – karu Jul 09 '14 at 17:48
  • 3
    No, *don't* do \globaldefs=1. Use \expandafter\gdef\csname node-#1\endcsname{#2} instead. – egreg Jul 09 '14 at 17:51
  • You mean like this?
    \gdef \DefineNode#1#2
    {
      \expandafter\gdef\csname node-#1\endcsname{#2}
    }
    
    

    It will produce:

    0.0
    1.0
    3.0
    4.0
    6.0
    7.0
    ! Undefined control sequence.
    \node-na.0 ->\tmpi
    
    – karu Jul 09 '14 at 18:16
  • Don't modify \globaldefs! \newcommand is a macro which does temporary assignments that don't need to be done globally. – Ulrich Diez Sep 30 '22 at 13:20

1 Answers1

5

A feature of \foreach is that it performs each cycle in a group; its main purpose was to add paths or nodes to a tikzpicture being built and this operation is indeed global.

Doing \globaldefs=1 is not a good workaround, because \newcommand performs several assignments that you really don't want to be global.

You can look at \global\renewcommand equivalent of \global\def for a \gnewcommand that doesn't require \globaldefs=1. However, in the case at hand, a simpler

\newcommand{\DefineNode}[2]{%
  \expandafter\xdef\csname node-#1\endcsname{#2}%
}

seems sufficient. You need \xdef in order to expand \tmpi and \tmpii.

You won't be warned about redefining the same control sequence. If you really need this feature, then

\makeatletter
\providecommand\@nameedef[1]{\expandafter\edef\csname#1\endcsname}
\newcommand{\DefineNode}[2]{%
  \expandafter\@ifdefinable\expandafter{\csname node-#1\endcsname}{%
    \global\@nameedef\node-#1}{#2}%
  }%
}
\makeatother

is what you're looking for. Again an expanded definition is necessary.

egreg
  • 1,121,712
  • I'm must be missing something. First one produces: 0.0 1.0 3.0 4.0 6.0 7.0 ! Undefined control sequence. \node-na.0 ->\tmpi Second one produces: ! Extra }, or forgotten \endgroup. – karu Jul 09 '14 at 18:39
  • @karu You have to use \xdef, of course, so \tmpi is expanded. With \globaldefs=1 you got no error, but wrong output. I have modified my answer to reflect this. – egreg Jul 09 '14 at 19:46