
Me he encontrado con un uso aparentemente idiomático en \pgf@marshal
todo el paquete PGF y me pregunto por qué se usa.
Por ejemplo de pgflibraryshapes.gates.logic.US.code.tex
:
{%
\edef\pgf@marshal{%
\noexpand\pgfpatharc{90}{-90}{\the\pgf@yc}%
}%
\pgf@marshal%
}
Probablemente sea fácil, pero ¿por qué no simplemente
\pgfpatharc{90}{-90}{\the\pgf@yc}
?
Respuesta1
Si bien \pgfpatharc
no se usa \pgf@yc
(al menos no hasta que ya haya sido evaluado y almacenado en otro lugar) y hubiera sido seguro hacerlo
\pgfpatharc{90}{-90}{\pgf@yc}
(sin el \the
par), elel propio manual advierte
Atención:PGF utiliza estos registros para realizar operaciones de ruta. Por razones de eficiencia, los comandos de ruta no siempre los protegen. En consecuencia, el código
\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@ya}}{\pgfpoint{\pgf@xb}{\pgf@yb}}
puede fallar: En el interior
\pgfpointadd
, los\pgf@xa
registros de amigos y pueden modificarse. En particular, puede ocurrir que\pgf@xb
se modifique antes de\pgfpoint{\pgf@xb}{\pgf@yb}
ser evaluado. Lo correcto sería expandir primero todo usando\edef
y luego procesar los valores, lo que resultaría en operaciones costosas e innecesarias. Por supuesto, esto se puede evitar simplemente mirando el código fuente de\pgfpointadd
para ver qué registros se utilizan.
(Curiosamente, el ejemplo dado realmente funcionaría, pero no
\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\pgfpoint{\pgf@xa}{\pgf@ya}}
porque las coordenadas del primer punto se almacenarán \pgf@xa
y \pgf@ya
luego se agregarán a las del segundo punto).
En el caso de \pgfpatharc
, #3
se evalúa antes de \pgf@yc
usarse y esto solo sucede en el ámbito, por lo que \pgf@yc
todavía tiene el mismo valor después \pgfpatharc
.
Entonces, sí, el desarrollador de la biblioteca de circuitos podría haber examinado la definición de \pgfpatharc
y podría haber determinado que no tiene sentido.
Pero hay otros puntos a considerar:
- Es posible que el
\pgfpatharc
comando haya funcionado de manera diferente al momento de escribir la biblioteca de circuitos. - El
\pgfpatharc
comando podría cambiar en el futuro. - En algún otro momento, el autor de la biblioteca de circuitos notó un conflicto y cambió todas las llamadas a macros similares para que nunca más tuvieran que lidiar con tales problemas.
Respuesta2
Otra perspectiva para aquellos que no están muy familiarizados con el modelo de ejecución TeX.
Wikcionario:
mariscal (verbo)
4. Recopilar datos para su transmisión.
5. (informática, transitiva) Para serializar un objeto en un estado ordenado representado por una secuencia de bytes que luego se puede convertir nuevamente en un objeto con propiedades equivalentes.
Mientras que en el contexto informático normalmente se desea el significado 5, en este caso el significado 4 parece ser más relevante. Pero también podría entenderse como "serializar el código en una lista de tokens y luego ejecutar la lista de tokens como un código" --- pero luego, en TeX, el código y la lista de tokens son prácticamente lo mismo.
tl;dr:
De forma predeterminada, los comandos TeX se ejecutan "de afuera hacia adentro", es decir, a diferencia de los lenguajes de programa típicos donde los "argumentos de función" se "evalúan" antes de "pasarse a la función", en TeX, el argumento se pasa al macro textualmente.
- en Python,
f(1+2)
yf(3)
es idéntico porque1+2
se evalúa3
antes def
recibirlo. En TeX,\f{\numexpr 1+2\relax}
y\f{3}
no es idéntico.
- en Python,
En este caso, como se explica enla otra respuesta, la persona que llama quiere evaluar el número antes de pasar a la función.
TeX tiene una cantidad muy limitada de mecanismos para manipular tokens. El código que ves es equivalente a algo como
eval(r"\pgfpatharc{90}{-90}{" + pgfyc + "}")
en la sintaxis de Python --- el código se manipula como una lista de tokens y luego se ejecuta.
La alternativa sería agregar
\expandafter
en todas partes del código, lo que definitivamente es menos eficiente. (También existe\expanded{\unexpanded{...}}
, pero no existía en el momento en que se escribió el código).Otros lugares donde se usa este modismo se pueden ver, por ejemplocómo utilizar
pgfplots
la trama en un buclecon\edef\temp{...}\temp
.El prefijo
pgf@
indica que el nombre de la macro es interno del paquete pgf. Si no está editando el código fuente de PGF/TikZ, debe crear su propio nombre y no reutilizarlo\pgf@marshal
.