2

I've encountered an apparently idiomatic use of \pgf@marshal all over the PGF package and I wonder why it is used.

For example from pgflibraryshapes.gates.logic.US.code.tex:

{%
    \edef\pgf@marshal{%
        \noexpand\pgfpatharc{90}{-90}{\the\pgf@yc}%
    }%
    \pgf@marshal%
}

This is probably an easy one, but why not just

\pgfpatharc{90}{-90}{\the\pgf@yc}

?

apriori
  • 953

2 Answers2

2

While \pgfpatharc doesn't use \pgf@yc (at least not until it has already been evaluated and stored somewhere else) and it would have been safe to do

\pgfpatharc{90}{-90}{\pgf@yc}

(without the \the even), the manual itself warns

Attention: PGF uses these registers to perform path operations. For reasons of efficiency, path commands do not always guard them. As a consequence, the code

\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@ya}}{\pgfpoint{\pgf@xb}{\pgf@yb}}

may fail: Inside \pgfpointadd, the \pgf@xa and friend registers might be modified. In particular, it might happen that \pgf@xb is changed before \pgfpoint{\pgf@xb}{\pgf@yb} is evaluated. The right thing to do would be to first expand everything using \edef and process the values afterwards, resulting in unnecessary expensive operations. Of course, one can avoid this by simply looking into the source code of \pgfpointadd to see which registers are used.

(Interestingly enough, the given example would actually work but not

\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}

because the coordinates of the first point will be stores in \pgf@xa and \pgf@ya to be later added to those of the second point.)

In the case of \pgfpatharc, #3 get evaluated before \pgf@yc gets used and this only happens scoped, so \pgf@yc still has the same value after \pgfpatharc.

So, yes, the developer of the circuits library could have taken a look into the defintion of \pgfpatharc and could have determined that there's no point.

But there are other points to be considered:

  • The \pgfpatharc command might have worked differently at the time of writing the circuits library.
  • The \pgfpatharc command might change in the future.
  • The author of the circuits library at some other point noticed a conflict and changed all similar macro calls so that they never have to deal with such problems again.
Qrrbrbirlbel
  • 119,821
0

Another perspective for those not very familiar with TeX execution model.


Wiktionary:

marshal (verb)
4. To gather data for transmission.
5. (computing, transitive) To serialize an object into a marshalled state represented by a sequence of bytes that can later be converted back into an object with equivalent properties.

While in computing context usually meaning 5 is desired, in this case meaning 4 appears to be more relevant. But it could also be understood as "serialize the code into a token list, then later execute the token list as a code" --- but then, in TeX, code and token list is mostly the same thing.

tl;dr:

  • By default, TeX commands are executed "from outside to inside" --- that is, unlike typical program languages where "function arguments" are "evaluated" before "being passed to the function", in TeX, the argument is passed to the macro verbatim.

    • in Python, f(1+2) and f(3) is identical because 1+2 is evaluated to 3 before f receives it. In TeX, \f{\numexpr 1+2\relax} and \f{3} is not identical.
  • In this case, as explained in the other answer, the caller want to evaluate the number early before passing to the function.

  • TeX has a very limited number of mechanism to manipulate tokens. The code you see is equivalent to something like

    eval(r"\pgfpatharc{90}{-90}{" + pgfyc + "}")
    

    in Python syntax --- the code is manipulated as a token list then executed.

    The alternative would be to add \expandafter everywhere in the code, which is definitely less efficient. (there's also \expanded{\unexpanded{...}}, but that didn't exist at the time the code is written.)

  • Other places this idiom is used can be seen in for example how to use pgfplots plot in a loop with \edef\temp{...}\temp.

  • The prefix pgf@ denotes that the macro name is internal to the pgf package. If you're not editing PGF/TikZ source code, you should make your own name and not reuse \pgf@marshal.

user202729
  • 7,143