# How to make \const{\length{\list}} work without modifying the implementation of \const?

\const does not work for the current definition. It is defined to easily declared constants in both TeX and PostScript scopes. For example, if I want to define a const Speed of a value 300000000, I can declare it with a single call \const{Speed}{300000000} which is known in both PS and TeX scopes. Another example, if I want to create a const NumberOfElements in PS and TeX scopes, I can call \const{NumberOfElements}{\length{\list}} where \length (defined as shown in the MWE) and \def\list{a,b,c}.

The problem is I have no knowledge to make \const{\length{\list}} work while keeping \const works as the original intent. Here is the MWE.

\documentclass[pstricks,border=12pt]{standalone}

% user defined data
\def\listX{1,2,3,4,5,6}
\def\listY{1,2,3}

% to determine the number of elements in a list
\newcounter{x}
\def\length#1{\setcounter{x}{0}\psforeach{\i}{#1}{\stepcounter{x}}\thex}

% to create constants in both TeX and PS scopes
\def\const#1#2{%
\expandafter\FPeval\csname#1\endcsname{#2}%
\pstVerb{/#1 \csname#1\endcsname\space def}%
}

\const{Nx}{\length{\listX}}
\const{Ny}{\length{\listY}}
\const{CellW}{1}
\const{CellH}{2}

\const{CanvasWidth}{Nx*CellW}
\const{CanvasHeight}{Ny*CellH}

\begin{document}

\begin{pspicture}[showgrid=bottom](\CanvasWidth,\CanvasHeight)
% use other PS constants here
\end{pspicture}

\end{document}


Bonus question: Is there a smarter way to know the number of elements in a list?

-
Could you try to come up with a more descriptive title to your question, one that is more specific? The current title could hopefully apply to any question we have here -- I don't think people ask questions that they can easily answer themselves. –  doncherry Jul 23 '12 at 14:07
This is a better title, but I don't think the works is grammatically correct. Howsabout omitting the word? –  Marc van Dongen Dec 30 '12 at 0:58
Great title.... –  Marc van Dongen Dec 30 '12 at 7:21

Let's see the matter in general, though a deep discussion would require many pages of a book.

You are concerned with definitions of commands, not only with nesting macro calls. The "working" definition

\def\const#1#2{\expandafter\def\csname#1\endcsname{#2}}


with the call

\const{Count}{\length{\list}}


is equivalent to

\def\Count{\length{\list}}


If you have also \def\list{1,2,3}, then

\const{Count}{\length{\list}}\Count


would print 3. However, if you say

\def\list{1,2,3}
\const{Count}{\length{\list}}
\Count

\def\list{a,b,c,d}
\Count


you'd get

3
4

Why? Because the macro \Count is defined in terms of \list, which will then use the current meaning of \list, not the one at definition time: \list is just a pointer to a token list (the current replacement text).

Your problem is to assign as the meaning \Count the current length of \list, independently from possible subsequent redefinitions. And you want it as a plain number, because you must pass it to \pstVerb as the replacement text of a PostScript token.

The way to cope with this is to perform the computations, store the numeric result in a temporary control sequence and then using \edef.

Here's a way:

\makeatletter
\newcount\const@count
\def\length#1{%
\const@count=\z@
\edef\@tempa{\number\const@count}%
}
\def\const#1#2{%
#2%
\expandafter\let\csname #1\endcsname\@tempa
\begingroup\edef\x{\endgroup
\noexpand\pstVerb{/#1 \@tempa\space def}}\x
}
\makeatother


Call this as

\const{Count}{\length{\list}}


The important thing is to perform the computation before defining \Count and doing \pstVerb.

This is analogous to what you're doing elsewhere with \FPeval.

First of all \length{\list} is computed and the result is stored in \@tempa with \edef, so that the actual number is the replacement text. Then \let will make \Count have the current meaning of \@tempa and then the \pstVerb is emitted, in an indirect way, to avoid any reference to \@tempa in the replacement text, thanks to \edef again.

Let' try to generalize this; I suggest a three argument macro:

\makeatletter
\def\const#1#2#3{% #1=name, #2=method, #3=data
#2{#1}{#3}%
\begingroup\edef\x{\endgroup
\noexpand\pstVerb{/#1 \csname#1\endcsname\space def}}\x
}
\newcount\const@count
\def\length#1#2{%
\const@count=\z@
\expandafter\edef\csname#1\endcsname{\number\const@count}%
}
\makeatother


Now \const{Count}{\length}{\list} or \const{ABC}{\FPeval}{2*3} will work.

If \FPeval is the default method, you can simplify the syntax:

\documentclass{article}

% user defined data
\def\list{1,2,3,4,5,6}

\makeatletter
\newcommand\const[3][\FPeval]{% #1=method, #2=name, #3=data
\expandafter#1\csname#2\endcsname{#3}%
\begingroup\edef\x{\endgroup
\noexpand\pstVerb{/#2 \csname#2\endcsname\space def}}\x
}
\newcount\const@count
\def\length#1#2{%
\const@count=\z@
\edef#1{\number\const@count}%
}
\makeatother

\begin{document}

\const[\length]{Count}{\list}
\Count

\const{ABC}{2*2}
\ABC
\end{document}

-

It is simplest if you work purely by expansion, then the behaviour of the TeX and PS constructs are more similar. I changed the syntax slightly using \ in the product expression to save parsing the tokens.

\documentclass[pstricks,border=12pt]{standalone}

% user defined data
\def\listX{1,2,3,4,5,6}
\def\listY{1,2,3}

% to determine the number of elements in a list
\makeatletter

\long\def\length#1{%
\expandafter\xlength\expandafter0#1,\relax,}

\long\def\xlength#1#2,{%
\ifx\relax#2%
\the\numexpr#1\relax
\expandafter\@gobblefour
\fi
\expandafter\xlength\expandafter{\the\numexpr#1+1\relax}}
\makeatother

% to create constants in both TeX and PS scopes
\def\const#1#2{%
\expandafter\edef\csname#1\endcsname{\the\numexpr#2\relax}%
\pstVerb{/#1 \csname#1\endcsname\space def}%
}

\const{Nx}{\length{\listX}}
\const{Ny}{\length{\listY}}
\const{CellW}{1}
\const{CellH}{2}

\const{CanvasWidth}{\Nx*\CellW}
\const{CanvasHeight}{\Ny*\CellH}

\begin{document}

\begin{pspicture}[showgrid=bottom](\CanvasWidth,\CanvasHeight)
% use other PS constants here
\end{pspicture}

\end{document}

-