Programación en Ada/Unidades genéricas
Polimorfismo paramétrico
editarLa idea de reutilización de código surge ante la necesidad de construir programas en base a componentes bien establecidos que pueden ser combinados para formar un sistema más amplio y complejo. La reutilización de componentes mejora la productividad y la calidad del software. El lenguaje Ada soporta esta característica mediante las unidades genéricas.
Una unidad genérica es aquella en la que se manipulan tipos que posteriormente instanciará el usuario, es decir, se utiliza a modo de plantilla. Se pueden hacer unidades genéricas de subprogramas y paquetes. Sintácticamente se podría describir como:
unidad_genérica ::=generic
{ lista_parámetros_genéricos } ( especificación_subprograma | especficicación_paquete ) lista_parámetros_genéricos ::= identificador { , identificador } [in
[out
] ] tipo [ := expresión ] ; |type
identificadoris
( (<>) |range
<> |digits
<> |delta
<> | definición_vector | definición_puntero ) | declaración_privada_de_tipo | declaración_formal_procedimiento | declaración_formal_paquete
Por ejemplo, para reutilizar un procedimiento de intercambio de variables:
generic
type
TElementois
private
; -- Parámetro tipo formal genérico.procedure
Intercambiar (X, Y:in
out
TElemento);
procedure
Intercambiar (X, Y:in
out
TElemento)is
Temporal : TElemento;begin
Temporal := X; X := Y; Y := Temporal;end
Intercambiar;
La especificación del subprograma va precedida por la parte formal genérica, que consta de la palabra reservada generic seguida por una lista de parámetros formales genéricos que puede ser vacía.
El subprograma Intercambiar es genérico y se comporta como una plantilla. Hay que destacar que las entidades declaradas como genéricas no son locales, por ello es necesario instanciarlas. Por ello, para poder utilizar la unidad del ejemplo es necesario crear una instancia suya para el tipo que se quiera usar, su sintaxis sería:
instanciación_unidad_genérica ::= (package
|procedure
|function
) identificadoris
new
identificador [ ( parámetro_instanciado { , parámetro_instanciado } ) ] ;
Por ejemplo:
procedure
Intercambiar_enterosis
new
Intercambiar (Integer);
Con ello, se puede utilizar el procedimiento para tipos Integer, si se quiere utilizar para cualquier otro tipo basta con volver a instanciarlo para el nuevo tipo con otro nombre o, si se utiliza el mismo identificador en la instanciación, se sobrecarga el procedimiento y puede ser utilizado para distintos tipos:
procedure
Interis
new
Intercambiar (Float);procedure
Interis
new
Intercambiar (TDía);procedure
Interis
new
Intercambiar (TElemento => TPila);
De igual modo, se pueden emplear paquetes genéricos, por ejemplo, para implementar una plantilla del tipo abstracto de datos pila:
generic
-- Especificación unidad genérica. Max: Positive; -- Parámetro bjeto formal genérico.type
TElementois
private
; -- Parámetro tipo formal genérico.package
Plantilla_pilais
procedure
Poner (E: TElemento);function
Quitarreturn
TElemento;end
Plantilla_pila;
package
body
Plantilla_pilais
-- Cuerpo unidad genérica. Pila: array(1..Max)of
TElemento; Cima: Integerrange
0..Max; -- ...end
Plantilla_pila;
Ahora se podría utilizar una pila de un tamaño y tipo determinados, para ello, habría que crear un ejemplar, por ejemplo, de esta manera:
declare
package
Pila_reales_de_100is
new
Plantilla_pila (100, Float);use
Pila_reales_de_100;begin
Poner (45.8); -- ...end
;
En la segunda línea del código anterior se ha creado una instancia del paquete Plantilla_pila
que se llama Pila_reales_de_100
. A partir de ese momento se pueden acceder a los miembros del paquete, ya que la creación de la instancia implica su visibilidad (igual que si se ejecutara la sentencia
).
with
Pila_reales_de_100;
Parámetros de unidades genéricas
editarResaltar que los objetos declarados como parámetros formales son de
modo in
por defecto y pueden ser in
o in
out
, pero nunca out
. En el caso
de que sea in
, se comportará como una constante cuyo valor lo
proporciona el parámetro real correspondiente. Como resulta obvio, un
parámetro genérico in
no puede ser de un tipo limitado, pues no se
permite la asignación y el parámetro formal toma su valor mediante
asignación. En el caso de que el parámetro genérico sea de modo in
out
,
se comporta como una variable que renombra al parámetro real
correspondiente; en este caso, el parámetro real debe ser el nombre de
una variable y su determinación se realiza en el momento de la creación
del ejemplar.
Además de parámetros genéricos de tipo y objetos, se pueden incluir parámetros formales de subprogramas o paquetes, por ejemplo:
generic
type
TElemis
private
;with
function
"*" (X, Y: TElem)return
TElem;function
cuadrado (X : TElem)return
TElem;
function
cuadrado (X: TElem)return
TElemis
begin
return
X * X; -- El operador "*" formal.end
cuadrado;
Se utilizaría, por ejemplo, con matrices (teniendo previamente definida la operación de multiplicación de matrices), de la siguiente manera:
with
Cuadrado;with
Matrices;procedure
Prueba_operacionesis
function
Cuadrado_matrizis
new
Cuadrado (TElem => Matrices.TMatriz, "*" => Matrices.Producto_matrices); A: TMatriz := TMatriz.Identidad;begin
A := Cuadrado_matriz (A);end
Prueba_operaciones;
Los tipos formales de un genérico se pueden especificar para que pertenezcan a una determinada clase de tipos.
Tipo formal | Instanciable con |
---|---|
|
Cualquier tipo con operador de igualdad y asignación definidos |
|
Cualquier tipo con discriminante de tipo TD |
|
Cualquier tipo con cualquier discriminante |
|
Cualquier tipo (sea limitado o no) |
|
Cualquier tipo discreto |
|
Cualquier tipo entero con signo |
|
Cualquier tipo de coma fija |
|
Cualquier tipo de coma flotante |
|
Cualquier tipo array con índice I y tipo de elementos E (I y E podrían ser a su vez otros parámetros formales) |
|
Cualquier tipo puntero que apunte a objetos de tipo O (O podría ser a su vez otro parámetro formal) |
En el cuerpo sólo podemos hacer uso de las propiedades de la clase de tipo del parámetro real. Es decir, a diferencia de las plantillas de C++, la especificación del genérico es un contrato que ha de cumplir la implementación.