|
|
En la industria y la academia se ha adoptado recientemente una nueva técnica para reutilizar componentes de programación: la parametrización [Str-89]. Esta técnica permite independizar los algoritmos de los datos, para obtener una solución más general. Esto es importante para lograr que un mismo algoritmo sirva para resolver problemas diferentes. Como muchas herramientas, la parametrización tiene varios usos, pero su aplicación más importante es en la construcción de contenedores, esto es, objetos que en un programa sirven para almacenar múltiples valores.
En este trabajo se muestra cómo lograr reutilizar componentes de programación aun si el lenguaje no tiene apoyo directo para usar parametrización, como ocurre con el lenguaje Pascal [JW-74]. Los resultados aquí obtenidos pueden ser aplicados fácilmente a otros lenguajes más avanzados, como Ada [ADA-86] y C++ [Str-98].
1.1 Motivación
La invención de las computadoras ha hecho necesario
desarrollar tecnologías de programación que les
permitan a los programadores construir mejores sistemas
computacionales, a un menor costo y con mayor velocidad, sin
sacrificar la calidad, la eficacia y la eficiencia en el proceso,
pues, conforme avanza el uso de computadores para resolver cada
vez más problemas, se hace necesario crear programas cada
vez más sofisticados.
Después de varias décadas se ha reconocido la necesidad de construir los sistemas computacionales por módulos [Boe-81]. Para definir módulos se deben usar varios grados de abstracción. Por eso son importantes los conceptos de Abstracción de Datos, Abstracción de Procedimientos y Abstracción de Iteración. Para hacer más robustos los programas, se han desarrollado técnicas como el Manejo de Excepciones, que se pueden simular en lenguajes primitivos como C [Lee-83] y Pascal [DiM-94j], pero que ya forman parte de los lenguajes más modernos como Ada y C++ , o Delphi [BI-95].
Los lenguajes modernos de más alto nivel, o sea, de mayor expresividad, incluyen construcciones sintácticas que apoyan directamente la abstracción y el manejo de excepciones. Precisamente esta es la diferencia más importante entre lenguajes de menor nivel, como Pascal [JW-74] y C [KR-86], y lenguajes más avanzados como Ada y C++, pues estos últimos incluyen paquetes genéricos, en el primer caso, y plantillas en el otro, para apoyar el uso de abstracción en los programas. Tanto C++ como Ada tienen apoyo directo para manejo de excepciones; ahora estos lenguajes también soportan el paradigma de programación orientada a los objetos [Str-88a]. En comparación con Ada y C++, C, o Pascal, es un Lenguaje de semántica limitada, pues le faltan algunas facilidades de abstracción que ya tienen esos dos lenguajes: parametrización y polimorfismo.
Para escribir programas muy sofisticados, como compiladores, sistemas operativos, o manejadores de sistemas de telecomunicación, es necesario todavía usar lenguajes procedimentales, principalmente C++ y Ada [Kri-97]. Aunque estos modernos lenguajes tienen construcciones que los hacen mucho más expresivos que los lenguajes arcaicos (Fortran [FOR-66], Cobol [COB-74], Algol [Nau-63] y PL/I [PL/I-76]), son lenguajes procedimentales porque han sido diseñados para que el código que produzca el compilador pueda ejecutarse eficientemente en las máquinas actuales [Str-98].
Lenguajes de más alto nivel como Prolog [CM-83], CLU [LG-86], Eiffel [Mey-88], ML [HMT-88], Smalltalk [GR-83] y Lisp [Ste-84], corresponden a máquinas virtuales que no pueden emularse eficientemente en los equipos actuales [PZ-98]. Por eso los programas que deben tener un alto desempeño no son escritos en lenguajes que utilizan sistemas de recolección de basura, (Prolog, ML, Lisp, CLU, Eiffel), semántica de referencia (ML, Lisp, CLU, Eiffel), ligamiento dinámico obligatorio (Smalltalk, Prolog) u otras construcciones que permiten aumentar significativamente la expresividad del lenguaje. De hecho, C++ es un lenguaje muy utilizado precisamente porque en C++ el programador mantiene control sobre el programa objeto que finalmente genera el compilador [Kri-97].
El profesor Niklaus Wirth diseñó Pascal al final de los sesentas [JW-74], y le incluyó las ventajas de los modernos lenguajes estructurados. Cuando Phillipe Kahn, dueño de la casa Borland, le incluyó a su compilador Turbo Pascal compilación separada, herencia y métodos virtuales, lo transformó en un lenguaje con apoyo directo para programación orientada a objetos. En las versiones más recientes del compilador, además de cambiarle el nombre al lenguaje por Delphi [BI-95], se le han incorporado construcciones sintácticas para el manejo de excepciones. Los compiladores para Pascal son muy rápidos y eficientes porque Pascal es un lenguaje simple y elegante. Pese a que ya Pascal no es el lenguaje preferido para programación de aplicaciones de alto rendimiento, es innegable que el compilador Turbo Pascal [BI-88], revolucionó el desarrollo de programas.
Por eso vale la pena contestar la siguiente pregunta: ¿Existe alguna forma de aumentar la expresividad del lenguaje Pascal para que sea posible implementar algoritmos que necesitan de avanzadas construcciones sintácticas en los otros lenguajes de alto nivel? Conviene usar la cualidades de Pascal para lograr crear una biblioteca reutilizable de contenedores, pues al hacerlo se aumentaría significativamente la capacidad de reutilización de componentes de programación. Al trasladar los resultados de esta investigación a otros lenguajes más poderosos, se les podrá sacar mejor provecho.
Para contestar afirmativamente esta pregunta, en esta disertación se han implementado eficientemente los contenedores más conocidos: el arreglo o vector, la lista y el árbol. El resultado es un grupo de módulos reutilizables que son parametrizables pese a que el lenguaje no tiene construcciones sintácticas para apoyar directamente la implementación. De esta manera se muestra que es posible usar parametrización de Tipos Abstractos de Datos (ADT: Abstract Data Type), en el caso de los contenedores, para lenguajes de capacidad semántica limitada. Más aún, al implementar la parametrización siguiendo los lineamientos que aquí se describen, se obtienen ventajas adicionales respecto a la forma tradicional de usar parametrización.
Aunque las ideas de esta tesis han sido desarrolladas para Turbo Pascal, los principios aquí descritos son aplicables a otras plataformas, en especial al lenguaje C++. Si posteriormente se demuestra que el aporte de este trabajo lo justifica, valdrá la pena producir una biblioteca C++ usando la tecnología desarrollada, pues la expresividad adicional que tiene C++ lo hace el candidato excelente para desarrollar un producto de calidad industrial con base en los resultados aportados en esta investigación. Como la implementación que se muestra en este trabajo es eficiente, posiblemente este trabajo puede tener un positivo impacto en el diseño de los nuevos lenguajes de computación que necesitamos para programar las máquinas del futuro. Más aún, es factible que la forma diferente de ver la programación de contenedores que aquí se presenta, sirva para mejorar la calidad de los programas y la forma en que se enseña Programación y Algoritmos en las Universidades.
1.2 Enfoque general
El
nivel de un lenguaje de computación es tanto más
alto cuanto mayor sea su Expresividad. Es
difícil medir la expresividad de un lenguaje, pero, para
hacerlo, los programadores simplemente escogen un problema
específico y lo resuelven usando diferentes lenguajes
[CM-83]. El lenguaje más
expresivo será aquel en el que la solución al
problema se puede expresar con mayor claridad, menor complejidad o
menos palabras. Por eso, todos los lenguajes de
programación siempre están orientados a resolver
problemas específicos.
Cada programador tiene preferencia por un lenguaje diferente, de acuerdo con sus necesidades. Algunos desean descubrir la forma más sucinta de expresar un algoritmo, por lo que relegan a un segundo plano consideraciones de rendimiento que acertadamente llaman Micro-eficiencias. A otros les interesa más bien llegar lo más rápidamente posible a la solución, aunque el programa que produzcan necesite usar más recursos en tiempo de ejecución. Y todavía hay un tercer grupo que busca sacar el mayor provecho posible de la máquina, aun a expensas de incrementar el costo de desarrollo del programa.
En el primer grupo están los programadores de Inteligencia
Artificial que usan lenguajes como Lisp o Prolog. Un ejemplo de la
expresividad de Prolog es el siguiente programa, que resuelve el
problema de las Torres de Hanoi con una sola instrucción
Move()
[CM-83] (pg 136-137):
hanoi(N) :- move(N, left, center, right).
move(0,_,_,_) :- !.
move(N,A,B,C) :-
M is N-1, move(M,A,C,B), w(A,B), move(M,C,B,A).
w(From,To) := write([move, from, From, to, To]), nl.
En este mismo grupo están los diseñadores de lenguajes funcionales o de lenguajes que soportan un alto grado de abstracción, como ML, CLU o Eiffel. En general, estos lenguajes liberan al programador del tedio de administrar la memoria dinámica, pues incluyen un recolector de basura que se activa en el momento en que ya no hay más memoria dinámica disponible [PZ-98]. Por eso estos lenguajes usan semántica de referencia, con lo que obvian la manipulación de diferentes tipos de datos y se facilita mucho la implementación de la parametrización y el polimorfismo.
Los programas escritos en lenguajes que usan recolectores de basura, pueden ejecutarse con eficiencia cuando hay una cantidad sobrada de recursos de computación: ciclos de ejecución, memoria y almacenamiento secundario. Pero cuando alguno de estos recursos es escaso, el programa puede entrar en "Revoloteo" (trashing), mientras se reacomodan los recursos disponibles para atender una nueva solicitud. Este revoloteo impide predecir el comportamiento del programa, por lo que este tipo de lenguajes no se usa para implementar aplicaciones críticas como sistemas operativos o sistemas de tiempo real.
El segundo tipo de programador quiere llegar lo más rápidamente posible a concretar la solución a su problema. El lenguaje usado en estos casos está altamente especializado para resolver el problema, lo que hace necesario que esté muy bien definido cuál es el tipo de solución a la que se debe llegar. En los Sistemas de Información se cumple este requisito, porque ya la industria ha logrado determinar con gran exactitud cuáles son los usos y limitaciones de estas aplicaciones.
Es en el mundo de los negocios donde principalmente se encuentran estas aplicaciones, y donde se destacan los Lenguajes de Cuarta Generación [4GL] y sus derivados, que sirven para construir sistemas de información a un costo reducido [Mar-85]. Como la mayor parte de los programadores trabajan construyendo sistemas de información, al disminuir el costo de producirlos se ha aumentado la productividad del programador promedio, lo que se traduce en un inmenso ahorro. Esto explica no sólo la buena fama de estos lenguajes, y su desarrollo actual (ahora les llaman Arquitectura de Cliente/Servidor), sino también el enorme esfuerzo financiero que se ha hecho para consolidarlos, pues prácticamente todos los Sistemas de Información actuales se desarrollan usando tecnologías 4GL o sus derivados.
En el tercer grupo de programadores están quienes se dedican a desarrollar las herramientas y los lenguajes que están más cerca de la máquina, y que son fundamentales para el desarrollo tecnológico de la computación. Son estos los programadores de los vídeo-juegos o quienes hacen los programas de tiempo real que controlan los pulmones artificiales a los que están conectados pacientes en estado comatoso o, también, quienes programan los computadores incluidos en los electrodomésticos modernos o en los automóviles, y son ellos también quienes programan los compiladores y los sistemas operativos que gobiernan nuestras estaciones de trabajo [Str-98].
Para este tercer tipo de programador es muy importante ahorrar tiempo de ejecución y memoria: a veces debe luchar varios días para ahorrarse un byte en el programa, o trabaja en la reprogramación del código producido por el compilador para aumentar la velocidad de ejecución. Son estos programadores quienes han abrazado a C++ como su plataforma de desarrollo, porque saben que en este lenguaje siempre estarán tan cerca de la máquina como lo necesiten, y son los mismos que no pueden pagar el costo de usar un lenguaje que utilice un recolector de basura, pues ello implica perder el control sobre el rendimiento efectivo del programa [Kri-97].
Hacia este tipo de programador está orientado este trabajo. Lo que se ha logrado en esta disertación es tomar un lenguaje de reducida capacidad expresiva, Pascal, para agregarle de una forma muy simple y eficiente las principales construcciones semánticas que se incluyen en otros lenguajes y que sirven para aumentarles su expresividad, sin por ello recurrir al uso de técnicas que afectan la eficiencia de los programas, como los recolectores de basura o la semántica de referencia.
Las bibliotecas de contenedores que se construyen usando las técnicas descritas en este trabajo, tienen la cualidad de que no requieren distribuir el código fuente de las implementaciones, lo que no ocurre con otras bibliotecas. Esta es una de las contribuciones fundamentales de esta investigación. Por eso, al aplicar los resultados aquí descritos, se aumenta la capacidad de reutilización de programas, que básicamente le permite a un programador usar el trabajo que otro ya ha hecho para construir su programa. De esta manera se mitiga un poco el problema de lograr reutilizar completamente todos los componentes de programación disponibles.
Lo importante en esta disertación no es crear construcciones sintácticas para aumentar la expresividad de los lenguajes de programación, pues de hecho esas construcciones ya están disponibles en varios lenguajes, como Ada y C++. Más bien lo que se hace aquí es implementar algoritmos de manera simple y eficiente, utilizando menos recursos, para mejorar de esta manera la reutilización de módulos. Así el programador tiene acceso a módulos reutilizables por los que no tiene que pagar un alto precio en velocidad de ejecución. Por eso estas ideas sirven para sugerir mejores formas de utilizar la expresividad de lenguajes como Ada y C++ sin afectar negativamente el rendimiento de los programas.
Podría calificarse este aporte como un nuevo "Paradigma de Construcción de Sistemas", pero más bien es "un buen método para reutilizar módulos". La importancia de esta contribución radica en que permite aumentar la reutilización del código sin sacrificar eficiencia. Por eso el auditorio al que está dirigido este trabajo, son aquellos programadores que todavía buscan cómo lograr ahorrar un bit y un nanosegundo en cada programa.
Además, en este trabajo también se definen un conjunto de convenciones para escribir programas Pascal que permiten que las instancias de los objetos, aun cuando están almacenados dentro de un contenedor, tengan asignada memoria en la pila de ejecución del programa; así se mejora la eficiencia de los programas que usan abstracción de datos. Este trabajo está orientado al compilador Turbo Pascal v5.5, aunque la misma técnica también puede usarse para Modula-2, sus sucesores, o en otras versiones de Pascal.
1.3 Ventajas de usar Pascal
El lenguaje Pascal tiene muchas cualidades que lo hicieron el
candidato óptimo para desarrollar este trabajo. Una de las
razones por la que fue elegido este lenguaje es que no
tiene facilidades para parametrización y
polimorfismo, lo que obligó al autor a afinar
su técnica para obtener resultados. En otras palabras, esta
carencia del lenguaje es su fortaleza, pues es gracias a ella que
se han obtenido los resultados expuestos en esta
investigación. Desde este punto de vista, usar C++ como
lenguaje de desarrollo no era lo más conveniente, pese a
que C++ es un lenguaje mucho más
expresivo que Pascal porque
cuenta con facilidades para usar
parametrización y
polimorfismo. Siempre es un reto lograr
metas minimizando la cantidad de recursos utilizados.
Otra alternativa para desarrollar esta investigación era usar el lenguaje C en lugar de Pascal. C fue desechado porque Pascal tiene las facilidades más importantes de programación orientada a objetos. Además, el compilador de Pascal es mucho más rápido que el de C. Otros lenguajes más sofisticados, como Ada, CLU y Eiffel, quedaron por fuera por la misma razón por la que se desechó C++, y porque es difícil conseguir los respectivos compiladores. En resumen, las cualidades que inclinaron la balanza a favor de Pascal son las siguientes:
A nivel mundial Pascal es un lenguaje muy popular, pues en muchas universidades es el primero que aprenden los estudiantes, lo que explica por qué hay tantos libros de texto sobre Pascal. Esto es conveniente, porque el estudio sobre abstracción que se incluye en esta investigación podrá ser aprovechado para mejorar la docencia en universidades, lo que ayudaría a que las ideas aquí expresadas tengan mayor difusión y uso.
1.4 Mezcla de inglés y español
Como muchos de los nombres, los identificadores y los
acrónimos usados en este trabajo se escriben en la lengua
inglesa, es necesario explicar por qué no se han usado
nombres en español. Las razones son las siguientes:
DISPOSE() es:
Retorne_Memoria_Dinámica();
Disponga(), pero suena un poco
cacofónico).ARRAY". Algunos términos
no tienen traducción directa, como "overhead", que
en este trabajo se translitera a
"sobretrabajo", o
"trashing", traducido aquí como
"revoloteo".Create(),
Reset() y
Destroy() para las
operaciones básicas, pero
luego todos los módulos fueron modificados para usar los
identificadores
Init(),
Clear() y
Done() que usa Borland en
sus bibliotecas. Luego el nombre Clear() fue cambiado
por
Erase(). Además,
Reset() es uno de los procedimientos que exporta la
unidad Dos.tpu.La razón más importante de por qué en este trabajo se usan identificadores en inglés, es que las especificaciones fueron hechas siguiendo los lineamientos de la casa Borland, productora del compilador Turbo Pascal. Por lo anterior, aunque la tesis está escrita en lengua española, muchos identificadores y acrónimos están escritos en inglés por simplicidad, facilidad y compatibilidad con la literatura existente. Para darle uniformidad a esta obra se siguen las convenciones de programación descritas en [DiM-88a], las que son ampliadas en este trabajo.
| 4GL | Fourth Generation Language |
| ADH | Adolfo Di Mare Hering |
| ADT | Abstract Data Type |
| HTML | HyperText Markup Language |
| DLL | Dynamic Link Library |
| OOP | Object Oriented Programming |
| Rep | Representación interna |
| STL | Standard Template Library |
| VMT | Virtual Method Table |
1.5 Organización de la disertación
El resto de la disertación está organizada como
sigue:
En el Capítulo 2 "Antecedentes" se describe el contexto general y la terminología usada en el resto del trabajo. Se discute el significado del concepto de abstracción desde el punto de vista de varios lenguajes y de varios formalismos, para concretar qué es un tipo abstracto de datos y qué es un contenedor. Además, se presentan las diversas formas de utilizar la abstracción que han sido propuestas por varios investigadores.
En el Capítulo 3 "Abstracción en Pascal" se definen las construcciones básicas necesarias para usar abstracción en el ámbito del lenguaje Pascal. La discusión es detallada y se presentan varios ejemplos y convenciones que ayudan a mejorar la calidad de los programas Pascal.
En el Capítulo 4 "Operaciones Básicas" están especificadas las operaciones que cualquier tipo abstracto de datos puede tener.
En el Capítulo 5 "Operaciones básicas de un contenedor" están especificadas las operaciones que caracterizan a los contenedores.
En el Capítulo 6 "Operaciones básicas de un iterador", se especifican las operaciones que sirven para obtener todos los valores almacenados en un contenedor. Aunque los iteradores pueden ser considerados tipos abstractos de datos, lo usual es que no tengan las operaciones básicas definidas en el Capítulo 4, sino otras diferentes que sirven para recorrer el contenedor.
En el Capítulo 7
"Parametrización de contenedores" se
introduce la unidad Pascal
Binder.pas que es la
piedra angular de esta obra. La biblioteca Binder.pas
se utiliza para implementar los dos contenedores más
importantes: el
Árbol y la
Lista. Aquí se explican las ideas y
métodos que permiten
implementar parametrización en la plataforma Turbo
Pascal v5.5.
En el Capítulo 8 "Análisis de resultados" se discuten las ventajas y desventajas del enfoque propuesto, y se analizan sus requerimientos. Se muestran además las limitaciones que presenta y la forma de vencerlas.
Finalmente, en el Capítulo 9 "Conclusión" se resume la contribución de este trabajo y se presentan algunas ideas para futuras investigaciones.
La contribución más importante de este trabajo está en el Capítulo 7 "Parametrización de contenedores", en donde se describe cómo alcanzar los objetivos propuestos en el Resumen de este obra. El otro aporte significativo es la especificación de las operaciones básicas de los Tipos Abstractos de Datos que está en los Capítulos 4, 5 y 6.
1.6 Guía de lectura
Tal vez el lector no puede invertir mucho tiempo en estudiar
este trabajo, para lo que le conviene seguir esta guía de
lectura. Lo más importante del trabajo está definido
en el
Resumen, que está en las
primeras páginas de la tesis, y en los aportes que se
mencionan en la
sección 9.1, aunque siempre
conviene leer todas las conclusiones, que están en el
Capítulo 9. Sin embargo, es
mejor entender cuál es el problema que se trata de
resolver, el cual se describe en el
Capítulo 2, especialmente en la
sección 2.2, que trata del
estado actual de la tecnología, y en la
sección 2.3, donde se
muestra la importancia de la investigación desarrollada. La
sección 2.1 es un compendio
histórico a través de los ojos del
autor, que le puede servir al
lector para entender, pero sólo un poco, su forma de
pensar.
En el Capítulo 3 "Abstracción en Pascal" se definen todos los vocablos que se usan en el resto del trabajo. Por ejemplo, al principio se define qué es un módulo, y qué significa esta palabra en el contexto de la investigación desarrollada. En la versión HTML de la tesis, que se puede leer con un hojeador Internet, se han incluido enlaces de hipertexto para saltar al punto en que cada definición aparece (como es el caso para el enlace que está bajo la palabra "módulo"). Casi todos los conceptos fundamentales para entender este trabajo están definidos en el Capítulo 3 (en otras palabras, los programadores expertos seguramente no leerán este capítulo, mientras que los profesores que lo usen, obligarán a sus estudiantes a leerlo varias veces). Es necesario mencionar que los términos que se usan aquí, a veces tienen significados un tanto diferentes a los que otros autores les dan. Por ejemplo, encapsular aquí no significa que dos objetos han sido definidos en el mismo módulo, como ocurre en otros trabajos, sino más bien que los objetos están asociados a nivel sintáctico en el lenguaje.
La investigación desarrollada se describe, con gran detalle, en el Capítulo 7 "Parametrización de contenedores". Luego, en el Capítulo 8, se compara la implementación desarrollada con una implementación tradicional. Por eso la contribución más significativa de esta investigación está en el Capítulo 7, y, por eso, ese es el capítulo más largo de la tesis. ¿Quién querrá leer el Capítulo 7? Quien quiera conocer en detalle la contribución de esta investigación. ¿Quién se saltará el Capítulo 8? Quien no necesite conocer con gran detalle cuáles limitaciones tiene el trabajo realizado, o quien simplemente desee examinar globalmente cuáles son las ideas nuevas que hay en este trabajo. Sin embargo, conviene mucho conocer el contenido del Capítulo 7 para entender las conclusiones, y también el aporte de esta investigación, que está en el Capítulo 9 y en la sección 9.1.
|
|
¿Hay algún diagrama que resuma todo el trabajo realizado? Por supuesto que sí: la técnica utilizada para implementar contenedores parametrizables se muestra en el diagrama de una lista parametrizable, en la Figura 7.4. Hay que contrastar ese diagrama con el que aparece en la Figura 7.3, que muestra la forma tradicional de implementar contenedores. La diferencia estriba en no considerar el campo de enlace del contenedor como un campo del valor almacenado, sino más bien como un requisito que debe cumplirse para reutilizar un contenedor parametrizable. El cambio en la codificación de programas que esto comporta es mínimo, pero resulta en una mejor reutilización del contenedor.
Al implementar los contenedores siguiendo el método descrito en este trabajo, se logra que todas las instancias del contenedor compartan la misma copia del módulo compilado. Esto representa una diferencia muy significativa respecto de los enfoques tradicionales, en los que la reutilización se logra únicamente a nivel de código fuente de los algoritmos, pues la especialización de cada módulo reutilizable se logra usando parametrización textual, lo que resulta en versiones compiladas diferentes para cada instanciación. También es por eso que los contenedores implementados de acuerdo con las ideas expuestas en este trabajo, tienen la ventaja adicional de que para reutilizarlos nunca es necesario distribuir los códigos fuente de los algoritmos, pues la reutilización se da a nivel del código compilado de los módulos de programación.
VAR
L : TList <INTEGER>;
{ ... }
L.Append(1);
L.Append(2);
|
TYPE
Tint = RECORD
i : INTEGER;
link : TLlink;
END;
VAR
L : TList;
n,m : Tint;
{ ... }
n.i := 1; L.Append(n.link);
m.i := 2; L.Append(m.link);
|
En el
Capítulo 7 se discute con gran
detalle la función de
Binder.pas, que es el
módulo que permite
compartir el código objeto de los contenedores porque es
ahí en donde se mantiene la información necesaria
para manipular los
elementos almacenados en el
contenedor. Las dos primeras secciones del
Capítulo 8 son interesantes
porque en la
sección 8.1 se contrasta el
estilo de programación que hay que usar para parametrizar
contenedores en Pascal con el estilo usual de programación
cuando se usan otras bibliotecas, como la biblioteca STL de C++
(ver
Figura 8.2). En la
sección 8.2 se definen
cuáles deben ser los requerimientos de una biblioteca de
contenedores parametrizables: es aquí en donde se argumenta
sobre la importancia de que todos los contenedores compartan el
código objeto, pues de esa manera se logra evitar entregar
el código fuente de los algoritmos.
Hay tres capítulos intermedios que tienen una gran cantidad de especificaciones escritas en Pascal: los capítulos cuatro, cinco y seis. Las especificaciones que se incluyen ahí sirven para concretar la maquinaria de programación que se desarrolla en el Capítulo 7, por lo que el conocedor de la materia puede querer leer estos capítulos por partes, sólo cuando necesita conocer exactamente la especificación de alguna operación que se menciona en el resto de la obra.
Para concretar, al lector experto le conviene leer los capítulos uno, dos, siete y nueve, aunque tal vez quiera hojear también el capítulo ocho. Un estudiante querrá pasar por todos los capítulos de la tesis, en su orden. Quien quiera conocer grosso modo de qué se trata este trabajo, se conformará con los capítulos uno, dos y nueve. Habrá quienes sólo quieren leer el capítulo seis, que trata de los iteradores en Pascal, pues en la literatura se habla poco sobre este tema. Un profesor puede querer usar el capítulo tres en uno de los primeros cursos de programación, pues contiene ejemplos y definiciones de los conceptos más importantes que se han desarrollado con la tecnología de programación. Quien trabaje implementando bibliotecas de programas, encontrará muy útil estudiar concienzudamente el contenido de los capítulos cuatro, cinco y seis. Tal vez al lector le sirva conocer el orden en que fueron escritos los capítulos de la tesis:
Copyright © 1999 Adolfo Di Mare
|
|
|