[UACA]
[<==] [\/] [/\] [==>]


Reutilización de Contenedores Parametrizables con Lenguajes de Semántica Limitada


Capítulo 9: Conclusión

¿Qué es un Clip?
Es un alambre bien doblado...
Carlos Loría

      Con el fin de propiciar el nacimiento de la biblioteca parametrizada STL [STL-95], en su libro The Design and Evolution of C++ [Str-84], Bjarne Stroustrup, el máximo exponente de C++, hace la siguiente afirmación:

"Las plantillas fueron consideradas esenciales para el adecuado diseño de clases de contenedores... Para muchas personas, el mayor problema de C++ es la falta de una librería estándar extensa. Un problema mayor al producir esa librería es que C++ no provee una facilidad suficientemente general para definir "clases contenedoras" como listas, vectores y arreglos asociativos."

      Esta afirmación de Stroustrup no es correcta, como se ha demostrado en este trabajo al implementar contenedores parametrizables con la ayuda de la unidad Pascal Binder.pas, en especial con la lista implementada en List.pas. En la sección 7.1, precisamente con la Figura 7.4, se describe en detalle la técnica que hay que usar para implementar contenedores parametrizables usando Binder.pas.

      La hipótesis inicial de trabajo para esta investigación ha quedado demostrada, pues efectivamente no se necesita de avanzadas construcciones semánticas para lograr la parametrización de contenedores. Por eso se puede afirmar que es posible reutilizar contenedores con lenguajes de semántica limitada, como, por ejemplo, Pascal, pese a que no cuenten con avanzadas construcciones sintácticas como plantillas o paquetes genéricos. Por eso es válido hacer estas afirmaciones:

      Es posible implementar contenedores parametrizables sin usar plantillas ni paquetes genéricos.

      Si es posible implementar contenedores polimórficos si el lenguaje no tiene apoyo directo para parametrización

      El lenguaje de programación más usado para implementar la mayor parte de los sistemas de computación avanzados es C++. Como C++ tiene soporte directo para todas las construcciones que se usaron en la implementación Pascal aquí descrita, se puede afirmar que los resultados obtenidos se pueden obtener también para el lenguaje C++. Lo interesante será obtener una biblioteca de contenedores reutilizables, similar a STL, pero con la particularidad de que la reutilización se haga a nivel de lenguaje de máquina, y no a nivel del código fuente de los algoritmos. En C++ se usarían las plantillas para obtener resultados similares al uso de la construcción TYPECAST discutida en la sección 7.9. Algunas de las ventajas de implementar STL con el apoyo de la tecnología que Binder.pas representa son las siguientes:

  1. No hay que sacrificar mucho en eficiencia.
  2. Todas las instancias del contenedor comparten el código compilado, lo que disminuye el tamaño de los programas y la complejidad de los sistemas.
  3. No es necesario que el código fuente de la biblioteca sea distribuido.
  4. Una misma implementación se puede usar en varias plataformas diferentes, módulo la recompilación de los programas.

      La principal deficiencia de la biblioteca STL, y en general de todas las bibliotecas tradicionales de contenedores, es que la reutilización se logra duplicando los algoritmos al instanciarlos por medio del polimorfismo textual que comporta el uso de plantillas o paquetes genéricos. Esta deficiencia se corrige si se usan las ideas desarrolladas en este trabajo.

9.1 Contribuciones de esta disertación [<>] [\/] [/\] [<>]

      La contribución más importante de este trabajo está plasmada en la implementación del contenedor List.pas. Al implementar los contenedores siguiendo las ideas desarrolladas en esta investigación, se alcanzan dos objetivos muy importantes. Primero, la reutilización se da a nivel del código compilado, y segundo, se evita distribuir los códigos fuente de los algoritmos. Al alcanzar estos dos objetivos, se allana el camino para que luego sea posible incluir dentro del sistema operativo, como un servicio adicional, una biblioteca de contenedores que pueda ser compartida por todos los programas, lo que ayudará a mejorar la eficiencia de los sistemas de cómputo. Esto no es posible si la reutilización de contenedores se continúa haciendo en la forma tradicional, usando parametrización textual mediante el uso de plantillas. Los resultados obtenidos descansan en un descubrimiento muy importante:

  L ─────>─┐
           │ ┌──────────────┐ ┌──────────────┐ ┌─> NIL
           v │              v │              v │
 ┌────────┬──┼┐   ┌────────┬──┼┐   ┌────────┬──┼┐
 │ elem_1 │ *┘│   │ elem_2 │ *┘│   │ elem_3 │ *┘│
 └────────┴───┘   └────────┴───┘   └────────┴───┘
      El campo de enlace que aparece en cada uno de los valores almacenados en un contenedor no le pertenece al elemento almacenado, sino que más bien le pertenece al contenedor, que es el encargado de manipularlo.
Figura 7.4: Diagrama de una lista parametrizable

      Desde esta óptica, cada elemento contiene un campo que le permite enlazarse en el contenedor: por eso, al implementar las operaciones del elemento, no es necesario saber cómo está hecho el campo de enlace. En otras bibliotecas nunca se ha hecho esta diferenciación, lo que ha impedido compartir el código compilado de los algoritmos y, por ende, ha resultado en una reutilización menos efectiva que la que se ha logrado aquí. Los contenedores parametrizados con Binder.pas se distinguen de los de cualquier otra biblioteca de programación porque siempre comparten la implementación de los algoritmos, pero sin usar semántica de referencia para lograrlo.

      El análisis de rendimiento realizado en la sección 8.4 muestra que el impacto de Binder.pas en el rendimiento de los programas es prácticamente insignificante, equivalente a agregar en algunas ocasiones un llamado indirecto a una subrutina. Aunque pueden existir programas en que ese precio sea inaceptable, en general los beneficios de Binder.pas justifican con creces el costo.

      En la implementación de Tree.pas se ha reutilizado la lista, sin necesidad de hacerle cambios al código fuente o al código compilado del módulo List.pas, lo que es prueba fehaciente de que se pueden construir contenedores reutilizables usando como herramienta a Binder.pas. Otras contribuciones importantes que se derivan del trabajo realizado son las siguientes:

9.2 Direcciones futuras de investigación [<>] [\/] [/\] [<>]

      Conviene mucho saber de dónde se ha partido al llegar al final de la jornada de trabajo, pues en ese momento se puede reflexionar sobre si se ha llegado adonde se quería, o a otro lado. Esta investigación nació de dos preguntas hechas por estudiantes. La primera es: "Profesor, ¿por qué no puso la lista en esa operación?"

  PROCEDURE Insert(

     p: ^Nodo;   i: INTEGER 
  );
  VAR
    pN: ^Nodo;
  BEGIN
    NEW(pN); pN^.val := i;

    pN^.next := p^.next;
    p^.next  := pN;
  END;  { Insert }
  PROCEDURE Insert(
     VAR L: TList;
     p: ^Nodo;   i: INTEGER 
  );
  VAR
    pN: ^Nodo;
  BEGIN
    NEW(pN); pN^.val := i;

    pN^.next := p^.next;
    p^.next  := pN;
  END;  { Insert }
Figura 9.1: Insert(p,i) vs Insert(L,p,i)

      Sucede que en la Figura 9.1 lo correcto es no omitir la variable "L" del encabezado para la operación List.Insert(), que agrega un nuevo valor a la lista en la posición "p":
      Insert(L,p,i)
Es irrelevante se se usa o no "L" en alguna implementación, pues toda especificación debe ser lo más general posible para permitir modificar y mejorar la implementación. En este caso particular, la especificación de la rutina incluye más información que la necesaria para realizar una implementación, que en este caso especial usa punteros. Para contestarle su pregunta al estudiante fue necesario replantear su trabajo para finalmente obtener un módulo ListC.pas cuya especificación fuera independiente de una implementación específica [DiM-94f].

      Después de salvar ese primer escollo, otro alumno preguntó: "Profesor, ¿no tiene un programita para evitar usar el editor de textos cada vez que necesito una lista?" Los estudiantes, al trabajar en un proyecto que requería varias listas diferentes, y en particular una lista que contenía listas, comenzaron a necesitar apoyo automatizado para parametrizar sus listas. En lugar de cambiar el lenguaje, surgió la idea de parametrizar contenedores sin usar plantillas, o sea, parametrizar aun si el lenguaje está limitado en su sintaxis. De ahí nace el título de este trabajo: "Reutilización de Contenedores Parametrizables con Lenguajes de Semántica Limitada".

      En esta investigación se logrado avanzar el estado del arte porque se han definido cuáles son los principios teóricos básicos necesarios para implementar la reutilización de componentes de programación, y luego se han usado para concretar una implementación reutilizable de contenedores parametrizables. Los resultados se han logrado buscando minimizar el uso de recursos, para al mismo tiempo aumentar la capacidad de reutilización de los componentes de programación. O sea, que se obtiene más funcionalidad con menos recursos.

      El siguiente paso es trasladar estos resultados al lenguaje C++, para producir una biblioteca muy eficiente de módulos reutilizables que pueda ser distribuida como un servicio adicional del sistema operativo, posiblemente en la forma de módulos compilados de tipo DDL, para ser usada desde cualquier lenguaje que tenga soporte directo para programación orientada a los objetos (OOP). En particular, conviene que la misma biblioteca pueda ser invocada desde programas escritos en varios lenguajes diferentes, especialmente en Ada, C++, Pascal y Eiffel.

#define Link_to_PObj(link) (...)

#ifndef NDEBUG
  // usa una función con prototipo
  bool InsertA(TList *L; TElem *e);
#else
  // hace la invocación "inline" con una macro
  #define InsertA(L,e) \
          InsertA_List(L, (TList_Tlink) Link_to_PObj((e)->link))
#endif
Figura 9.2: Transliteración al lenguaje C

      Los primeros pasos en esta dirección ya se han dado, pues el autor ya ha comenzado a trasladar los resultados obtenidos en este trabajo al lenguaje C [DiM-99a] y [DiM-99b]. En el segundo artículo, titulado "C parametrized lists", se muestra que la ideas desarrolladas al producir el módulo Binder.pas se pueden transliterar con facilidad al lenguaje C, pese a que C no cuenta con apoyo directo para OOP. Como se muestra en la Figura 9.2 esta deficiencia de C es suplida con el uso del preprocesador, pero logrando compartir una única copia del código compilado.

      A partir de los resultados obtenidos, también se puede lograr otras metas:

      Muchos programadores nunca aprenden a usar contenedores en sus programas; para ellos la parametrización será un concepto complicado y, por ende, nunca podrán parametrizar contenedores con Binder.pas. Para otros, las ideas usadas para construir Binder.pas serán una técnica más que sirve para implementar bibliotecas parametrizables de alto nivel. En este caso, Binder.pas y sus módulos asociados serán una biblioteca de bajo nivel. Tal vez otros descubran cómo usar mejor Binder.pas.

      Es posible que algunos programadores nunca acepten implementar un contenedor usando apuntadores entre los campos de enlace, que es el estilo de programación que da sustento a Binder.pas. Pero tal vez esta resistencia sea igual a la que experimentaron, en la década de los años setentas, quienes se opusieron a la eliminación de la instrucción GO TO [Dj-75], pues después de quejarse por algunos años, simplemente adoptaron el nuevo estilo de programación sin mayor problema. El tiempo se encargará de discernir qué es lo cierto.

      ¡Ojalá la parametrización de contenedores que se ha descrito en este trabajo llegue a ser, al menos, una fracción de lo útil que es un "Clip"!

Copyright © 1999 Adolfo Di Mare
Derechos de autor reservados © 1999 Adolfo Di Mare <adolfo@di-mare.com>
[<==] [/\] [<>] [<>] [/\] [==>]