Continuamos con la introducción al lenguaje Pascal Moderno.

Esta entrada es una traducción al español, del texto original escrito por Michalis Kamburelis.

Units

Las unidades le permiten agrupar cosas comunes (cualquier cosa que se pueda declarar), para que las usen otras unidades y programas. Son equivalentes a módulos y paquetes en otros idiomas. Tienen una sección de interfaz, donde declara lo que está disponible para otras unidades y programas, y luego la implementación. Guarde la unidad MyUnit como myunit.pas (en minúsculas con la extensión .pas).

Los programas finales se guardan como archivos myprogram.lpr (lpr = archivo de programa Lazarus; en Delphi usaría .dpr). Tenga en cuenta que aquí son posibles otras convenciones, p. algunos proyectos solo usan .pas para el archivo de programa principal, algunos usan .pp para unidades o programas. Aconsejo usar .pas para unidades y .lpr para programas FPC/Lazarus.

Un programa puede utilizar una unidad mediante una palabra clave uses:

Una unidad también puede contener secciones de inicialización y finalización. Este es el código que se ejecuta cuando el programa comienza y finaliza.

Unidades que se llaman unas a otras

Una unidad también puede usar otra unidad. Se puede usar otra unidad en la sección de interfaz, o solo en la sección de implementación. El primero permite definir cosas públicas nuevas (procedimientos, tipos…) además de las cosas de otra unidad. Este último es más limitado (si usa una unidad solo en la sección de implementación, puede usar sus identificadores solo en su implementación).

No está permitido tener dependencias de unidades circulares en la interfaz. Es decir, dos unidades no pueden usarse entre sí en la sección de interfaz. La razón es que para «comprender» la sección de interfaz de una unidad, el compilador primero debe «comprender» todas las unidades que utiliza en la sección de interfaz. El lenguaje Pascal sigue estrictamente esta regla y permite una compilación rápida y una detección completamente automática en el lado del compilador de las unidades que se deben volver a compilar. No hay necesidad de usar complicados archivos Makefile para una tarea simple de compilación en Pascal, y no hay necesidad de volver a compilar todo solo para asegurarse de que todas las dependencias se actualicen correctamente.

Está bien hacer una dependencia circular entre unidades cuando al menos un «uso» está solo en la implementación. Por lo tanto, está bien que la unidad A use la unidad B en la interfaz y luego la unidad B use la unidad A en la implementación.

Calificando identificadores con nombre de unidad

Diferentes unidades pueden definir el mismo identificador. Para mantener el código fácil de leer y buscar, por lo general debe evitarlo, pero no siempre es posible. En tales casos, la última unidad en la cláusula de usos «gana», lo que significa que los identificadores que introduce ocultan los mismos identificadores introducidos por unidades anteriores.

Siempre puede definir explícitamente una unidad de un identificador dado, usándolo como MyUnit.MyIdentifier. Esta es la solución habitual cuando el identificador que desea utilizar desde MyUnit está oculto por otra unidad. Por supuesto, también puede reorganizar el orden de las unidades en su cláusula de usos, aunque esto puede afectar otras declaraciones además de la que está tratando de arreglar.

En el caso de las unidades, recuerda que tienen dos cláusulas de uso: una en la interfaz y otra en la implementación. La regla de que las unidades posteriores ocultan las cosas de las unidades anteriores se aplica aquí de forma coherente, lo que significa que las unidades utilizadas en la sección de implementación pueden ocultar los identificadores de las unidades utilizadas en la sección de interfaz. Sin embargo, recuerde que al leer la sección de la interfaz, solo importan las unidades utilizadas en la interfaz. Esto puede crear una situación confusa, donde el compilador considera diferentes dos declaraciones aparentemente iguales:

La unidad Graphics (de Lazarus LCL) define el tipo de TColor. Pero el compilador no podrá compilar la unidad anterior, alegando que no implementó un procedimiento ShowColor que coincida con la declaración de la interfaz. El problema es que la unidad GoogleMapsEngine también define un tipo TColor. Y se usa solo en la sección de implementación, por lo tanto, sombrea la definición de TColor solo en la implementación. La versión equivalente de la unidad anterior, donde el error es obvio, se ve así:

La solución es trivial en este caso, simplemente cambie la implementación para usar explícitamente TColor desde la unidad de gráficos. También podría solucionarlo moviendo el uso de GoogleMapsEngine, a la sección de interfaz y antes que Gráficos, aunque esto podría tener otras consecuencias en casos reales, cuando UnitUsingColors definiría más cosas.

Exponer los identificadores de una unidad de otra

A veces desea tomar un identificador de una unidad y exponerlo en una nueva unidad. El resultado final debería ser que el uso de la nueva unidad hará que el identificador esté disponible en el espacio de nombres.

A veces, esto es necesario para preservar la compatibilidad con versiones anteriores de la unidad. A veces es bueno «ocultar» una unidad interna de esta manera.

Esto se puede hacer redefiniendo el identificador en su nueva unidad.

Tenga en cuenta que este truco no se puede hacer tan fácilmente con procedimientos, funciones y variables globales. Con procedimientos y funciones, podría exponer un puntero constante a un procedimiento en otra unidad (consulte Devoluciones de llamada (también conocidas como eventos, también conocidas como punteros a funciones, también conocidas como variables de procedimiento)), pero eso parece bastante sucio.

La solución habitual es entonces crear funciones triviales de «envoltura» que debajo simplemente llaman a las funciones desde la unidad interna, pasando los parámetros y devolviendo valores.

Para que esto funcione con variables globales, se pueden usar propiedades globales (a nivel de unidad), consulte Propiedades

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio esta protegido por reCAPTCHA y laPolítica de privacidady losTérminos del servicio de Googlese aplican.

El periodo de verificación de reCAPTCHA ha caducado. Por favor, recarga la página.