Tema 12: Creación de unidades
Curso: Curso de Pascal, por Nacho Cabanes
Curso de Pascal. Tema 12: Creación de unidades.
Comentamos en el tema 10 que en muchos lenguajes de programación podemos manejar una serie de bibliotecas externas (en ingles, library) de funciones y procedimientos, que nos permitían ampliar el lenguaje base.
En Turbo Pascal, estas bibliotecas reciben el nombre de "unidades"
(unit), y existen a partir de la versión 5. También existen en otras versiones de Pascal recientes, como Free Pascal.
En su momentos, empleamos la unidad CRT, que nos daba una serie de facilidades para manejar la pantalla en modo texto, el teclado y la generación de sonidos sencillos.
Iremos viendo otras unidades estándar cuando accedamos a la pantalla en modo gráfico, a los servicios del sistema operativo, etc. Pero hoy vamos a ver cómo podemos crear las nuestras propias.
¿Para qué? Nos podría bastar con teclear en un programa todas las funciones que nos interesen. Si creamos otro programa que las necesite, pues las copiamos también en ese y ya está, ¿no?
¡ NO ! Las unidades nos ayudan a conseguir dos cosas:
- La primera es que los programas sean más modulares. Que podamos dejar aparte las funciones que se encargan de batallar con el teclado, por ejemplo, y en nuestro programa principal sólo esté lo que realmente tenga este programa que lo diferencie de los otros. Esto facilita la legibilidad y con ello las posibles correcciones o ampliaciones.
- La segunda ventaja es que no tenemos distintas versiones de los mismos procedimientos o funciones. Esto ayuda a ganar espacio en el disco duro, pero eso es lo menos importante. Lo realmente interesante es que si se nos ocurre una mejora para un procedimiento, todos los programas que lo usen se van a beneficiar de él automáticamente.
Me explico: imaginemos que estamos haciendo un programa de rotación
de objetos en tres dimensiones. Creamos nuestra biblioteca de funciones,
y la aprovechamos para todos los proyectos que vayamos a hacer en tres
dimensiones. No solo evitamos reescribir en cada programa el procedimento
RotaPunto, p.ej.., que ahora se tomará de nuestra unidad "MiGraf3D", sino que si descubrimos una forma más
rápida de rotarlos, todos los programas que utilicen el procedimiento
RotaPunto se verán beneficiados sólo con recompilarlos.
Pero vamos a lo práctico...
Una "unit" tiene dos partes: una pública, que
es aquella a la que podremos acceder, y una privada, que es el desarrollo
detallado de esa parte pública, y a esta parte no se puede acceder
desde otros programas.
La parte pública se denota con la palabra "interface", y la privada con "implementation".
Debajo de interface basta indicar los nombres de los procedimientos que queremos "exportar", así como las variables, si nos interesase crear alguna. Debajo de implementation escribimos realmente estos procedimientos o funciones, tal como haríamos en un programa normal.
Veamos un ejemplito para que se entienda mejor.
Nota: este ejemplo NO SE PUEDE EJECUTAR. Recordemos que
una Unit es algo auxiliar, una biblioteca de funciones y procedimientos
que nosotros utilizaremos DESDE OTROS PROGRAMAS. Después de
este ejemplo de Unit incluyo un ejemplo de programa cortito que la emplee.
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Unidad que "mejora" }
{ la CRT }
{ MICRT1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
unit miCrt1;
interface { Parte "pública", que se exporta }
procedure AtXY( X, Y: byte ; texto: string );
{ Escribe un texto en ciertas coordenadas }
implementation { Parte "privada", detallada }
uses crt; { Usa a su vez la unidad CRT }
procedure AtXY( X, Y: byte ; texto: string );
begin
gotoXY( X, Y); { Va a la posición adecuada }
write( texto );
end;
end. { Final de la unidad }
Este ejemplo declara un procedimiento "AtXY" que hace un GotoXY
y un Write en un solo paso.
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Programa que usa la }
{ unit "MICRT1" }
{ PMICRT1.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program PruebaDeMiCrt1;
uses miCrt1;
begin
AtXY( 7, 5, 'Texto en la posición 7,5.' );
end.
Este programa no necesita llamar a la unidad CRT original, sino que
nuestra unidad ya lo hace por él.
Ahora vamos a mejorar ligeramente nuestra unidad, añadiéndole un procedimiento "pausa":
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Unidad que mejora la }
{ CRT (segunda versión) }
{ MICRT2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
unit miCrt2; { Unidad que "mejora más" la CRT }
{-------------------}
interface { Parte "pública", que se exporta }
procedure AtXY( X, Y: byte ; texto: string );
procedure Pausa;
{-------------------}
implementation { Parte "privada", detallada }
uses crt; { Usa a su vez la unidad CRT }
var tecla: char; { variable privada: el usuario no
puede utilizarla }
procedure AtXY( X, Y: byte ; texto: string );
begin
gotoXY( X, Y); { Va a la posición adecuada }
write( texto );
end;
procedure Pausa; { Pausa, llamando a ReadKey }
begin
tecla := ReadKey; { El valor de "tecla" se pierde }
end;
{-------------------}
end. { Final de la unidad }
Un programa que usase esta unidad, junto con la CRT original podría ser:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Prueba de la unidad }
{ MICRT2 }
{ PMICRT2.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program PruebaDeMiCrt2;
uses crt, miCrt2;
begin
ClrScr; { De Crt }
atXY( 7, 5, 'Texto en la posición 7,5.' ); { de miCrt2 }
pausa; { de miCrt2 }
end.
Finalmente, hay que destacar que las unidades pueden contener más cosas además de funciones y procedimientos: pueden tener un "trozo de programa", su código de inicialización, como por ejemplo:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Unidad que mejora la }
{ CRT (tercera versión) }
{ MICRT3.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
unit miCrt3; { Unidad que "mejora más" la CRT }
{-------------------}
interface { Parte "pública", que se exporta }
var EraMono: boolean; { Variable pública, el usuario puede
acceder a ella }
procedure AtXY( X, Y: byte ; texto: string );
procedure Pausa;
{-------------------}
implementation { Parte "privada", detallada }
uses crt; { Usa a su vez la unidad CRT }
var tecla: char; { variable privada: el usuario no
puede utilizarla }
procedure AtXY( X, Y: byte ; texto: string );
begin
gotoXY( X, Y); { Va a la posición adecuada }
write( texto );
end;
procedure Pausa; { Pausa, llamando a ReadKey }
begin
tecla := ReadKey; { El valor de "tecla" se pierde }
end;
{-------------------} { Aquí va la inicialización }
begin
if lastmode = 7 { Si el modo de pantalla era monocromo }
then EraMono := true { EraMono será verdadero }
else EraMono := false; { si no => falso }
end. { Final de la unidad }
y el programa podría usar la variable EraMono sin declararla:
{--------------------------}
{ Ejemplo en Pascal: }
{ }
{ Prueba de la unidad }
{ MICRT3 }
{ PMICRT3.PAS }
{ }
{ Este fuente procede de }
{ CUPAS, curso de Pascal }
{ por Nacho Cabanes }
{ }
{ Comprobado con: }
{ - Free Pascal 2.2.0w }
{ - Turbo Pascal 7.0 }
{ - Tmt Pascal Lt 1.20 }
{--------------------------}
program PruebaDeMiCrt3;
uses crt, miCrt3;
begin
ClrScr; { De Crt }
atXY( 7, 5, 'Texto en la posición 7,5.' ); { de miCrt3 }
if not EraMono then
atXY ( 10, 10, 'Modo de color ' );
pausa; { de miCrt3 }
end.
Se podría hablar mucho más sobre las unidades, pero intentaré ser breve:
-
Al compilar una unidad se crea un fichero con extensión .TPU (.PPU para Free Pascal), al que se puede
acceder desde nuestros programas con dos condiciones: que empleemos la
misma versión de compilador (el formato de estos ficheros variaba
en cada versión de Turbo Pascal, y quizá también entre versiones de Free Pascal), y que sepamos cómo es la parte pública
(interface).
- En Turbo Pascal 7 para MsDos, cada unidad tiene su propio segmento de código (esto va para quien conozca la estructura de la memoria en los PC), así que cada unidad puede almacenar hasta 64k de procedimientos o funciones. Los datos son comunes a todas las unidades, con la limitación 64k en total (un segmento) para todos los datos (estáticos) de todo el programa. Si queremos almacenar datos de más de 64k en el programa, tenga una o más unidades, deberemos emplear variables dinámicas, distintas en su manejo de las que hemos visto hasta ahora (estáticas), pero eso ya lo veremos el próximo día... :-)
Esta vez no propongo ejercicios. Que cada uno se construya las units que quiera, como quiera, y vaya consultando dudas...
Actualizado el: 08-07-2012 12:31