Las unidades genéricas en Ada son una característica poderosa que permite la creación de componentes de software reutilizables y flexibles. Las unidades genéricas pueden ser procedimientos, funciones, paquetes o tareas que se parametrizan con tipos, constantes, subprogramas u otras unidades genéricas. Esto permite escribir código que puede adaptarse a diferentes tipos de datos y comportamientos sin duplicar el código.

Conceptos Clave

  1. Plantillas Genéricas: Definición de una unidad genérica que puede ser instanciada con diferentes parámetros.
  2. Instanciación: Proceso de crear una versión específica de una unidad genérica con parámetros concretos.
  3. Parámetros Genéricos: Tipos, constantes, subprogramas u otras unidades genéricas que se pasan a la unidad genérica.

Definición de Unidades Genéricas

Paquetes Genéricos

Un paquete genérico se define utilizando la palabra clave generic seguida de la lista de parámetros genéricos. Aquí hay un ejemplo de un paquete genérico que define una pila (stack):

generic
   type Element_Type is private;
package Generic_Stack is
   procedure Push(Item : in Element_Type);
   procedure Pop(Item : out Element_Type);
   function Is_Empty return Boolean;
end Generic_Stack;

Instanciación de Paquetes Genéricos

Para usar un paquete genérico, se debe instanciar con tipos específicos. Aquí hay un ejemplo de cómo instanciar el paquete Generic_Stack con un tipo específico:

package Integer_Stack is new Generic_Stack(Element_Type => Integer);

Procedimientos y Funciones Genéricos

Los procedimientos y funciones también pueden ser genéricos. Aquí hay un ejemplo de una función genérica que encuentra el máximo de dos valores:

generic
   type T is private;
   with function "<" (Left, Right : T) return Boolean;
function Max (X, Y : T) return T;

Instanciación de Procedimientos y Funciones Genéricos

Para instanciar una función genérica, se debe proporcionar el tipo y la función de comparación:

function Max_Integer is new Max(T => Integer, "<" => "<");

Ejemplo Práctico

Definición de un Paquete Genérico

Vamos a definir un paquete genérico para una lista enlazada simple:

generic
   type Element_Type is private;
package Generic_Linked_List is
   type Node;
   type Node_Ptr is access Node;
   type Node is record
      Data : Element_Type;
      Next : Node_Ptr;
   end record;

   procedure Insert_First(List : in out Node_Ptr; Item : in Element_Type);
   procedure Delete_First(List : in out Node_Ptr; Item : out Element_Type);
   function Is_Empty(List : Node_Ptr) return Boolean;
end Generic_Linked_List;

Implementación del Paquete Genérico

package body Generic_Linked_List is
   procedure Insert_First(List : in out Node_Ptr; Item : in Element_Type) is
      New_Node : Node_Ptr := new Node;
   begin
      New_Node.Data := Item;
      New_Node.Next := List;
      List := New_Node;
   end Insert_First;

   procedure Delete_First(List : in out Node_Ptr; Item : out Element_Type) is
      Temp : Node_Ptr;
   begin
      if List /= null then
         Item := List.Data;
         Temp := List;
         List := List.Next;
         Free(Temp);
      else
         raise Constraint_Error with "List is empty";
      end if;
   end Delete_First;

   function Is_Empty(List : Node_Ptr) return Boolean is
   begin
      return List = null;
   end Is_Empty;
end Generic_Linked_List;

Instanciación y Uso del Paquete Genérico

with Generic_Linked_List;
procedure Test_Linked_List is
   package Integer_Linked_List is new Generic_Linked_List(Element_Type => Integer);
   use Integer_Linked_List;

   List : Node_Ptr := null;
   Item : Integer;
begin
   Insert_First(List, 10);
   Insert_First(List, 20);
   Insert_First(List, 30);

   while not Is_Empty(List) loop
      Delete_First(List, Item);
      Put_Line(Integer'Image(Item));
   end loop;
end Test_Linked_List;

Ejercicios Prácticos

Ejercicio 1: Paquete Genérico de Cola

  1. Definición: Define un paquete genérico para una cola (queue) que permita operaciones de encolar (enqueue) y desencolar (dequeue).
  2. Instanciación: Instancia el paquete genérico con el tipo Integer.
  3. Uso: Escribe un procedimiento que use la cola para almacenar y procesar una serie de números enteros.

Solución del Ejercicio 1

Definición del Paquete Genérico

generic
   type Element_Type is private;
package Generic_Queue is
   type Node;
   type Node_Ptr is access Node;
   type Node is record
      Data : Element_Type;
      Next : Node_Ptr;
   end record;

   type Queue is record
      Head : Node_Ptr;
      Tail : Node_Ptr;
   end record;

   procedure Enqueue(Q : in out Queue; Item : in Element_Type);
   procedure Dequeue(Q : in out Queue; Item : out Element_Type);
   function Is_Empty(Q : Queue) return Boolean;
end Generic_Queue;

Implementación del Paquete Genérico

package body Generic_Queue is
   procedure Enqueue(Q : in out Queue; Item : in Element_Type) is
      New_Node : Node_Ptr := new Node;
   begin
      New_Node.Data := Item;
      New_Node.Next := null;
      if Q.Tail /= null then
         Q.Tail.Next := New_Node;
      else
         Q.Head := New_Node;
      end if;
      Q.Tail := New_Node;
   end Enqueue;

   procedure Dequeue(Q : in out Queue; Item : out Element_Type) is
      Temp : Node_Ptr;
   begin
      if Q.Head /= null then
         Item := Q.Head.Data;
         Temp := Q.Head;
         Q.Head := Q.Head.Next;
         if Q.Head = null then
            Q.Tail := null;
         end if;
         Free(Temp);
      else
         raise Constraint_Error with "Queue is empty";
      end if;
   end Dequeue;

   function Is_Empty(Q : Queue) return Boolean is
   begin
      return Q.Head = null;
   end Is_Empty;
end Generic_Queue;

Instanciación y Uso del Paquete Genérico

with Generic_Queue;
with Ada.Text_IO; use Ada.Text_IO;
procedure Test_Queue is
   package Integer_Queue is new Generic_Queue(Element_Type => Integer);
   use Integer_Queue;

   Q : Queue := (Head => null, Tail => null);
   Item : Integer;
begin
   Enqueue(Q, 10);
   Enqueue(Q, 20);
   Enqueue(Q, 30);

   while not Is_Empty(Q) loop
      Dequeue(Q, Item);
      Put_Line(Integer'Image(Item));
   end loop;
end Test_Queue;

Conclusión

En esta sección, hemos aprendido sobre las unidades genéricas en Ada, cómo definirlas, instanciarlas y usarlas. Las unidades genéricas son una herramienta poderosa para crear componentes de software reutilizables y flexibles. A través de ejemplos prácticos, hemos visto cómo aplicar estos conceptos en la creación de estructuras de datos genéricas como pilas y colas. En el siguiente módulo, exploraremos los paquetes hijos y cómo se pueden utilizar para organizar y modularizar aún más el código en Ada.

© Copyright 2024. Todos los derechos reservados