ada - Cuándo usar Pragma Pure/Preelaborate
elaboration (2)
¿Existe un conjunto de reglas / pautas generales que puedan ayudar a entender cuándo preferir pragma Pure
, pragma Preelaborate
o algo más? Las reglas y definiciones presentadas en la norma (Ada 2012) son un poco pesadas y agradecería leer algo que es un poco más claro y orientado hacia el caso promedio.
Si quisiera ser concienzudo sin entender completamente el "por qué" de eso, ¿puedo simplemente intentar:
- Marque la especificación del paquete con
pragma Pure;
- Si no se compila, intente
pragma Preelaborate;
- Si eso falla, entonces he hecho algo complicado y necesito
pragma Elaborate
unidades en unawith
by by, o repensar el diseño del paquete.
Si bien esto podría funcionar (¿lo hace?), Porque se recomienda marcar un paquete como Puro siempre que sea posible (también con Preelaborate), sin embargo, parece un poco dañado y prefiero entender el proceso un poco mejor.
pragma Pure
Debe usar esto en cualquier paquete que no tenga un estado interno. Le dice al usuario del paquete que las llamadas a cualquier subprograma no pueden tener efectos secundarios, ya que no hay un estado interno que puedan cambiar. Por lo tanto, una función declarada a nivel de biblioteca dentro de un paquete puro siempre devolverá el mismo resultado cuando se llame con los mismos parámetros.
La implementación de Ada puede almacenar en caché los valores de retorno de las funciones de un paquete puro y omitir las llamadas a subrutinas si no se utilizarán sus valores de retorno debido a estos requisitos. Sin embargo, puede violar las restricciones llamando a subrutinas importadas (por ejemplo, desde una biblioteca C) dentro de su paquete puro (esto puede cambiar algún estado interno que el compilador de Ada no conoce). Si eres malo, incluso puedes importar subrutinas Ada de otras partes del software con pragma Import
para evitar los requisitos de pragma Pure
. No hace falta decir: si estás haciendo algo como esto, no uses pragma Pure
.
Edición: para aclarar las circunstancias en las que se pueden omitir las llamadas, permítanme citar el ARM :
Si una unidad de biblioteca se declara pura, entonces la implementación puede omitir una llamada en un subprograma a nivel de biblioteca de la unidad de biblioteca si los resultados no son necesarios después de la llamada. De manera similar, puede omitir tal llamada y simplemente reutilizar los resultados producidos por una llamada anterior en el mismo subprograma, siempre que ninguno de los parámetros sea de un tipo limitado, y las direcciones y valores de todos los parámetros reales por referencia, y la Los valores de todos los parámetros reales de copia, son los mismos que en la llamada anterior. Este permiso se aplica incluso si el subprograma produce otros efectos secundarios cuando se le llama.
GNAT, por ejemplo, define además que cualquier subrutina que tome un parámetro de tipo System.Address
o un tipo derivado de él no se considerará puro incluso si está definido en un paquete puro, porque la ubicación a la que apunta la dirección puede modificarse, pero GNAT no sabe a qué tipo de estructura apunta la dirección y, por lo tanto, no puede realizar ninguna comprobación sobre si se ha cambiado el valor de referencia del parámetro.
pragma Preelaborate
Esto le dice al compilador que el paquete no ejecutará ningún código en el momento de la elaboración (es decir, antes de que el procedimiento principal comience a ejecutarse). En el momento de la elaboración, se ejecutarán las siguientes construcciones:
- Inicialización de variables de nivel de biblioteca (esto puede ser una llamada de función)
- Inicialización de tareas declaradas a nivel de biblioteca (pueden comenzar a ejecutarse antes de que lo haga el procedimiento principal)
- Declaraciones en un
begin ... end
bloquebegin ... end
a nivel de biblioteca
Por lo general, debes evitar estas cosas si no las necesitas. Use pragma Preelaborate
siempre que sea posible, le dice a la persona que llama que puede usar el paquete de manera segura sin ejecutar nada en el momento de la elaboración.
Si algo no se compila con uno de estos pragmas cuando crees que debería, investiga por qué no se compila. Puede ayudarlo a descubrir problemas con la implementación o estructura de su paquete. No solo sueltes el pragma cuando no se compile. Como la restricción afecta las posibles restricciones en cualquier paquete que dependa de la suya, siempre debe elegir el pragma aplicable más estricto.
El manejo de órdenes de elaboración en GNAT es una guía útil. Idealmente, las reglas estándar serán suficientes para la mayoría de los programas. Los pragmas le dicen al compilador que sustituya su orden de elaboración. Deben aplicarse para resolver problemas específicos, en lugar de usarlos empíricamente.
Anexo: @ajb subraya una distinción importante entre los pragmas. El artículo citado concuerda con el enfoque descrito en la pregunta (viñetas uno y dos): "En consecuencia, una buena regla es marcar las unidades como Pure
o Preelaborate
si es posible, y si esto no es posible, marcarlas como Elaborate_Body
si es posible". Continúa discutiendo situaciones (punto tres) "donde ninguno de estos tres pragmas se puede usar".