La definición de un subprograma consta de tres elementos: (1) cabecera, donde se fija su clase y nombre, se describen sus parámetros formales y, si es una función, se especifica el tipo de su resultado, terminando todo ello con la palabra "is", expresando que a continuación se desarrolla el subprograma, (2) declaraciones locales, de cualquier elemento declarable (tipos, variables, constantes, ...), incluyendo la definición anidada de otros subprogramas y (3) el bloque de sentencias ejecutables del subprograma delimitado por las palabras reservadas "begin" y "end" (esta última suele ir acompañada del nombre del subprograma). Si el subprograma es una función, entre las sentencias ejecutables debe incluirse al menos una sentencia de retorno ("return") con una expresión que indique el valor a devolver a quien la llamó; si la ejecución de una función alcanza el final sin encontrar una sentencia de retorno, se produce una excepción "Program_Error", dado que la sentencia de retorno se utiliza en las funciones para especificar el valor a devolver. En los procedimientos puede omitirse la sentencia de retorno cuando el único punto de retorno se encuentra al final, como en el siguiente ejemplo.
procedure Intercambia(A,B: in out Integer)
is
C: integer;
begin
C := A;
A := B;
B := C;
end Intercambia;
function Media(A,B: Float) return Float is
begin
return (A + B) / 2.0;
end Media;
Las declaraciones locales están sujetas a las reglas de ámbito generales de Ada.
Un subprograma puede constituir por sí mismo una unidad de librería o estar anidado dentro de una unidad mayor. Si un subprograma está anidado en una unidad mayor, la definición del subprograma debe escribirse en una sección de declaraciones de esa unidad.
procedure Principal
is
...
procedure Intercambia(A,B: in out Integer)
is
...
begin
...
end Intercambia;
...
begin
...
end Principal;
En un mismo ámbito se pueden tener varios subprogramas con el mismo nombre, siempre que se diferencien en los parámetros o en el tipo del resultado (si son funciones). Esto se conoce como sobrecarga de subprogramas. La sobrecarga de operadores es una clase de sobrecarga de subprogramas.
...
procedure Intercambia(A,B: in out Integer)
is
...
begin
...
end Intercambia;
...
procedure Intercambia(A,B: in out Float)
is
...
begin
...
end Intercambia;
...
En determinadas circunstancias (p.e. cuando un subprograma se proporciona para ser usado desde un paquete, cuando se define un subprograma genérico o cuando hay referencias mutuas entre subprogramas) se precisa escribir una declaración de un subprograma separada de su definición. La declaración de un subprograma es como su cabecera, pero terminada en ";" en vez de con la palabra "is", para expresar que lo que se está dando es una vista de un subprograma cuya definición se haya en otro lugar.
procedure Intercambia(A,B: in out Integer);
function Media(A,B: Float) return Float;
La definición de un subprograma que está anidado en otra unidad puede extraerse de la misma para compilarse por separado, dejándolo indicado en la unidad matriz mediante una declaración con cláusula "separate". A efectos de reglas de ámbito es como si la definición del subprograma estuviera donde está dicha declaración. El subprograma separado debe indicar quién es su unidad matriz.
procedure Ejemplo_Matriz
is
...
-- Indicación de que Intercambia se desarrollará aparte
procedure Intercambia(A,B: in out Integer)
is separate;
...
begin
...
end Ejemplo_Matriz;
-- Lo siguiente posiblemente irá en un fichero diferente
separate(Ejemplo_Matriz)
procedure Intercambia(A,B: in out Integer)
is
...
begin
...
end Intercambia;
...
La llamada a un procedimiento constituye una sentencia, mientras que la llamada a una función sólo puede hacerse como parte de una expresión:
Intercambia(X,Y);
Z := Media(L,M);
if Media(L,M) > 5.0 then ...
return Media(L,M);
procedure Muchos_Parámetros(A,B: in Integer; C: out Float; L, M: in out Integer);
...
Intercambia(X,Y); -- A, toma el valor de X y B el de Y
...
La correspondencia entre parámetros formales y reales también puede hacerse por nombre: especificando los nombres del parámetro formal y del real, relacionándolos con una flecha ("=>"):
...
Intercambia(A => X,B => Y); -- A, toma el valor de X y B el de Y
...
A un parámetro formal de entrada se le puede hacer corresponder como parámetro real cualquier expresión del tipo adecuado; a los parámetros formales de salida o de entrada/salida sólo les pueden corresponder parámetros reales que sean variables.
Es posible especificar un valor por defecto para los parámetros de entrada asignándolo detrás del nombre del tipo.
procedure Defecto(A,B: in Integer := 0; C: in Float:= 0.0);
Si un parámetro formal tiene un valor por defecto no es necesario pasar ningún parámetro real, pero si después hay parámetros no omitidos, habrá que hacerlos corresponder por nombre.
Defecto(X,Y); -- A, toma el valor de X, B el de Y y C toma
el valor 0.0
Defecto(X); -- A, toma el valor de X, B el valor 0 y C el valor
0.0
Defecto(X,C => Z); -- A, toma el valor de X, B el valor 0 y C el de Z
generic
type Tipo is private;
with function "<"(X,Y: Tipo) return
Boolean;
type Indice is (<>);
type Lista is array(Indice range <>)
of Tipo;
procedure Ordenar(L: in out Lista);
procedure Ordenar(L: in out Lista) is
Menor: Indice;
Aux : Tipo;
begin
for I in L'First..Indice'Pred(L'Last)
loop
Menor := I;
for J in Indice'Succ(I)..L'Last
loop
if L(J)
< L(Menor) then
Menor := J;
end if;
end loop;
if Menor /= I then
Aux := L(I);
L(I) := L(Menor);
L(Menor) := Aux;
end if;
end loop;
return;
end Ordenar;
Una vez se tiene escrito el subprograma genérico, se pueden declarar instancias del mismo con diferentes parámetros reales genéricos, lo que hará que el compilador cree los subprogramas correspondientes. Para ilustrarlo, se proporciona un procedimiento llamado "Prueba" en cuya cláusula de contexto se incluye la unidad "Ordenar". El procedimiento "Prueba" declara dos instancias del procedimiento "Ordenar", aplicadas a arrays de elementos de tipo Integer y rango Integer (o Docena), que se diferencian sólo en la operación de ordenación. Cuando el compilador elabore estas declaraciones, se dispondrá de dos procedimientos no genéricos ("Ordena_Vector_Ascendente" y "Ordena_Vector_Descendente" ) que podrán ser utilizados, normalmente, igual que si se hubiesen escrito explícitamente.
with Text_Io,Ordenar;
use Text_Io;
procedure Prueba is
subtype Docena is Integer range
1..12;
type Vector is array(Integer
range <>) of Integer;
procedure Ordena_Vector_Ascendente is
new Ordenar(Integer,"<",Integer,Vector);
procedure Ordena_Vector_Descendente is
new Ordenar(Integer,">",Docena,Vector);
V: Vector(Docena);
...
begin
...
Ordena_Vector_Ascendente(V);
...
end Prueba;
© Grupo de Estructuras de Datos y Lingüística Computacional - ULPGC.
Anterior | Superior | Siguiente