Ada (linguaggio di programmazione): differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
+generics
Riga 462:
end Padre.Figlio_Privato;
 
</syntaxhighlight>
 
=== Generics ===
In Ada le routine o i package possono avere dei parametri risolti staticamente a tempo di compilazione, specificati facendo precedere l'unità dalla keyword <code>generic</code> e specificati tra parentesi tonde quando si istanzia l'unità generica. I generics sono un meccanismo statico che consente un riuso del codice, permettendo di istanziare la stessa unità con parametri di tipo differenti, ma a differenza di altri linguaggi i parametri generici possono essere non solo tipi, ma anche valori o routine. Nel caso di package generici, non può essere usata su essi la clausola <code>use</code> (può essere usata solo sulle loro istanze concrete) ed ogni eventuale loro package figlio deve necessariamente essere generico.<ref>{{cita|Barnes (2014)|pp. 469 ss.|barnes14}}.</ref>
 
Ad esempio, una procedura per scambiare due elementi può essere parametrizzata rispetto al tipo degli stessi
 
<syntaxhighlight lang=ada>
generic
type T is private;
procedure Scambia(A, B: in out T);
 
procedure Scambia(A, B: in out T) is
Temp: T;
begin
Temp := A;
A := B;
B := Temp;
end Scambia;
</syntaxhighlight>
 
ed essere istanziata per l'uso su tipi diversi:<ref>{{cita|Barnes (2014)|p. 470|barnes14}}.</ref>
 
<syntaxhighlight lang=ada>
procedure Scambia_Interi is new Scambia (Integer);
procedure Scambia_Float is new Scambia (Float);
</syntaxhighlight>
 
Analogamente un package può implementare uno stack generico
 
<syntaxhighlight lang=ada>
generic
type T is private;
Capacità: Positive;
package Stack is
procedure Push(X: T);
function Pop return T;
private
A: array (1 .. Capacità) of T;
Posizione: Integer range 0 .. Capacità;
end Stack;
</syntaxhighlight>
 
che può essere istanziato per contenere oggetti di differente tipo e scegliendo di volta in volta la capacità massima:<ref>{{cita|Barnes (2014)|p. 471|barnes14}}.</ref>
 
<syntaxhighlight lang=ada>
package Int_Stack is new Stack (Integer, 100); -- stack con una capacità di 100 valori interi
package Float_Stack is new Stack (Float, 50); -- stack con una capacità di 50 valori float
</syntaxhighlight>
 
==== Parametri di tipo ====
Nel caso più semplice, un parametro di tipo generico è istanziabile e ha solo la definizione di assegnamento e uguaglianza. Possono essere specificati diversi attributi del parametro di tipo, che ne modificano l'interfaccia: può essere limitato, può avere dei discriminanti (anche non specificati, indicati con il ''box'' <code><></code>, in tal caso il tipo non è istanziabile), può essere tagged, astratto, può essere discendente di un tipo preesistente o può essere un'interfaccia con una o più interfacce progenitrici. Alcuni esempi di parametri di tipo generici:<ref>{{cita|Barnes (2014)|p. 475|barnes14}}.</ref>
<syntaxhighlight lang=ada>
generic
type A is private; -- tipo privato
type B is limited; -- tipo limitato
type C (X: Integer); -- tipo con discriminante X
type D (<>); -- tipo con discriminante sconosciuto
type E is tagged; -- tipo tagged
type F is new T; -- tipo derivato dal tipo non tagged T
type G is new T with private; -- tipo derivato dal tipo tagged T
type H is interface and I and J; -- tipo interfaccia con due progenitrici
package Generic_Package is
...
end Generic_Package;
</syntaxhighlight>
 
Per i tipi enumerativi e numerici esistono anche delle indicazioni particolari, e per ognuno di essi sono disponibili le operazioni predefinite per tale tipo.<ref>{{cita|Barnes (2014)|p. 477|barnes14}}.</ref>
 
<syntaxhighlight lang=ada>
generic
type A is (<>); -- tipo enumerativo
type B is range <>; -- tipo numerico con segno
type C is mod <>; -- tipo numerico modulare
type D is digits <>; -- tipo in virgola mobile
type E is delta <>; -- tipo in virgola fissa
type F is delta <> digits <>; -- tipo decimale
</syntaxhighlight>
 
==== Parametri routine ====
Poiché per un tipo generico si assume l'esistenza delle sole funzioni predefinite per quella categoria di tipi, può essere necessario passare come parametro anche una o più routine. Ad esempio, implementando un [[albero binario di ricerca]] che possa contenere chiavi di un tipo qualsiasi, per effettuare le operazioni di inserimento o ricerca è necessario poter comparare le chiavi, ma l'operatore di confronto <code><</code> non è predefinito per ogni tipo. Si può quindi ovviare al problema passando tale operatore come parametro generico. I parametri generici per le routine devono essere quindi passati esplicitamente quando si istanzia il package, ma possono essere omessi se nella dichiarazione del parametro generico si specifica <code>is <></code>. In questo caso la routine viene scelta automaticamente quando si istanzia il package, a patto che sia definita e visibile, sia unica e abbia completa ''type conformance'' con la dichiarazione del parametro generico.<ref>{{cita|Barnes (2014)|pp. 485-491|barnes14}}.</ref>
 
<syntaxhighlight lang=ada>
-- package generico
generic
type T is private;
with function "<"(Sinistra, Destra: T) return Boolean is <>;
package Albero_Binario is
...
end Albero_Binario;
 
-- package che usa l'Albero_Binario
package P is
type Data is
record
...
end record;
function Confronta_Data(Sinistra, Destra: Data) return Boolean;
 
-- istanzia il package generico sul tipo Data
package Albero_Data is new Albero_Binario(Data, Confronta_Data);
 
-- l'operatore può anche essere omesso, perché esiste ed è visibile per il tipo Float
package Albero_Float is new Albero_Binario(Float);
end P;
</syntaxhighlight>