Fou dissenyat pensant en la seguretat i amb una filosofia orientada a la reducció d'errors comuns i difícils de descobrir. Per això es basa en el tipat fort i en verificacions en temps d'execució (desactivables en benefici del rendiment). La sincronització de tasques es realitza mitjançant la primitiva de comunicació síncrona rendez-vouz (cat.: trobada).[2][3]
Ada es fa servir principalment en entorns en què es necessita una gran seguretat i fiabilitat, com pot ser la defensa, l'aeronàutica (Boeing o Airbus), la gestió del trànsit aeri (com Indra a l'Estat espanyol) i la indústria aeroespacial (ESA) entre d'altres, en estreta relació amb els Sistemes operatius de Temps Real.[4]
predefinits: Float (precisió simple de 6 dígits), Long_Float (precisió doble de 15 dígits), ...
typePercentatgeisdigits4range0.0..1.0-- coma-flotant precisió amb restricció de rang
coma-fixa
coma-fixa binaris o bé decimals quan s'especifica la precisió.
la clàusula delta precisa el valor incremental (el factor per al valor emmagatzemat), és a dir, la resolució del tipus.
les operacions entre coma-fixes de delta diferents són més ràpides si les deltes són potència de la base.
typeDuradaisdeltaResolució_rellotge-- coma-fixa binaritypeCentim_DEuroisdelta0.01digits14-- coma-fixa decimal quan incorpora precisió en dígits,-- pels coma-fixa decimals la delta (resolució) ha d'ésser obligatòriament potència de deu.
Entrada / Sortida específica per tipus
Els mòduls d'entrada sortida són genèrics. Per imprimir o llegir valors, cal obtenir una instància del genèric adequat per al tipus específic.
-- instància del genèric 'Integer_IO' per a la precisió Long_IntegerpackageLong_Integer_IOis newAda.Text_IO.Integer_IO(Long_Integer)-- instància del genèric 'Float_IO' per a la precisió Long_FloatpackageLong_Float_IOis newAda.Text_IO.Float_IO(Long_Float)-- instància del genèric 'Fixed_IO' (coma-fixa) per al tipus específictypeKilo_Octetisdelta2.0**10;packageKilo_Octet_IOis newAda.Text_IO.Fixed_IO(Kilo_Octet);-- instància del genèric 'Enumeration_IO' per al tipus específictypeDiscretis(OPCIO_A,OPCIO_B);packageDiscret_IOis newAda.Text_IO.Enumeration_IO(Discret);-- instància del genèric 'Modular_IO' per al tipus específictypeByteismod2**8;packageByte_IOis newAda.Text_IO.Modular_IO(Byte);
Atributs
atributs dels tipus, després d'un apòstrof com el genitiu de l'idioma anglès (per ex.: John's car)[9]
-- lecturaPositive'First-- el primer del tipus-- escripturaforTipus'AtributuseValorNouDeLAtribut-- modificació d'atributs actualitzables
Constructor del tipus i conversions
-- constructor i components especificant '(x ,..) l'atribut per defecte: el constructor K:Positive:=Positive'(10)-- conversió amb NomDelTipus(expressió)Percentatge(Valor/100.0)
Tipus derivats i subtipus
tipus derivats: amb new el compilador els discrimina
categories: subtipus (acceptats en paràmetres del tipus)
-- Amb ''access''/''access constant'' només poden apuntar dins el propi dipòsit de dades (''storage pool'')typePunterARegistreis[not_null]accessRegistre-- accés RW (només pot apuntar dins el dipòsit de dades del tipus)typePunterARegistreis[not_null]accessconstantRegistre-- accés RO-- Amb ''access all'' els punters no tenen restriccions d'apuntament.typePunterARegistreis[not_null]accessallRegistre-- accés RW (all: sense restricció de dipòsit d'apuntament)
Per assignar un nou valor a l'objecte apuntat cal desreferenciar el punter amb .all (equival en C a prefixar un punter amb l'asterisc: * punter)
limited: per al cas d'estructures amb punters, prohibeix les operacions d'assignació (:=) i comparació (=) que ho fan bit a bit (superficials). (Per exemple, la comparació estructural de nodes encadenats no estaria garantida amb (=) doncs només compara bit-a-bit les primeres cel·les)
typeTuplaisrecord-- no limitat, admet assignació (:=) i comparació bit a bit (=) del registreA,B:Boolean;end record;typeLlistaislimitedrecord-- limitat, assignació (:=) i comparació bit a bit (=) prohibides-- la comparació estructural, quan hi ha punters, no es pot basar -- en la igualtat bit a bit de la primera cel·la.Cap:Integer;Cua:accessconstantLlista-- PunterALlista end record;
Vectors, Tipus paramètrics, Variants
vectors
typeVectorDeSencersisarray(1..10)ofInteger-- exemple d'ús amb inicialització -- (el d'índex 1 => 15, el segon 16, altres => valor_per_defecte)VA:VectorDeSencers:=(1=>15,2=>16,others=>0)
generictypeItemisprivate;-- paràmetre de tipus opac typePomaisrange<>;-- paràmetre de tipus enter, <>: abstracte en el rang typeMassisdigits<>;-- paràmetre de tipus coma flotant, <>: abstracte en la precisió typeAngleisdelta<>;-- paràmetre de tipus coma fixa binari, <>: abstracte en la resolució (valor mínim)typeEsdevenimentis(<>);-- paràmetre de tipus enumerable (pels parèntesis) <>: abstracte en els valorstypeBuffer(Length: Natural)islimitedprivate;-- paràmetre de tipus indexat -- (limited: assig. i comparació superficials prohibides (quan hi ha punters)) (private: opac)typeTableisarray(Esdeveniment)ofItem;-- paràmetre de tipus vector amb tipus d'elements i d'índex declarats prèviament
Ada permet a l'usuari un control fi de la gestió de memòria així com definir els seus propis gestors.[14]
Tipus de gestors
Gestors d'allotjament de mem. dinàmica (Storage_Pool) assignables a diferents tipus de dades[15][16]
Munt d'allotjament (ang: heap) principal de vida il·limitada
Amb el tipus de gestor Unbounded_No_Reclaim de System.Pool_Global
Segons la ref. el recol·lector de brossa no hi passa.[17] Al codi, però no a l'estàndard, hi diu: Allotjament per defecte dels tipus de punters declarats globalment.[18]GNAT de GNU permet associar-hi un recol·lector de brossa recompilant GCC amb --enable-objc-gc incorporant la biblio. libobjc-gc.a si l'arquitectura la suporta.[19]
Munt d'allotjament amb vida associada a un àmbit
Amb el tipus de gestor Unbounded_Reclaim_Pool de System.Pool_Local.
Quan l'execució surt de l'àmbit on el munt (Storage Pool) està definit, se'n reclama la memòria.[16] Al codi, però no a l'estàndard, hi diu: Allotjament per defecte dels tipus de punters declarats localment.[20] Sembla que era una pràctica en alguns compiladors de l'Ada83. AdaCore parla d'associació explícita.[16] Vegeu exemple #Allotjament dinàmic i Memòria d'àmbit.
Local_Pool:System.Pool_Local.Unbounded_Reclaim_Pool;-- munt reclamat en sortir de l'àmbitforPunter_A_T'Storage_PooluseLocal_Pool;-- en sortir de l'àmbit, el Local_Pool queda inaccessible-- i se n'executa automàticament el mètode ''Finalize'' que n'allibera la memòria.
Munt d'allotjament a la pila
Amb tipus de gestor Stack_Bounded_Pool de System.Pool_Size, per reservar memòria dinàmica a la pila de manera acotada.
Allotja elements d'un únic tipus.[21] El manual de AdaCore diu que aquest mòdul no està pensat per un ús directe per l'usuari, i que és el que es fa servir automàticament quan s'especifica el nombre d'elements per al tipus de punter.[16]
forPunter_A_T'Storage_Sizeuse10_000;-- reserva un Stack_Bounded_Pool per a 10000 elems. del tipus
Tipus de punters
Punters (clàusula access) restringits a apuntar només a elements de l'Storage_Pool associat al seu tipus.[14]
typePunter_A_SencerisaccessInteger;forPunter_A_Sencer'Storage_PooluseNom_del_Pool;-- assignació de Storage_Pool específic a un tipus
Punters no restringits (clàusula: access all): permet apuntar a elements de qualsevol Storage_Pool
Punters amb accés de només lectura (clàusula: access constant)[22]
aliased
Qualificador per indicar que un element d'una estructura pot ser accedit per punter i evitar que l'optimitzador del compilador l'empaqueti.[23]
Registres amb membres punters i restricció de còpia/comparació superficials
Les operacions d'assignació (:=) i comparació (=) són superficials (bit a bit), no tenen en compte si el registre conté punters.
Es pot retornar un registre (tipus compost) com a resultat d'una funció.
El qualificador limited: prohibeix assignacions i comparacions superficials (bit a bit) per a tipus que designin estructures de més profunditat (per quan hi ha punters, per ex. llistes encadenades).[24]
Allotjament i desallotjament de dades referides per punters
Directives de compilació (Pragma) relacionades amb la memòria
Pragma Controlled
Pragma per evitar que el recol·lector de memòria brossa (si l'habilitem), gestioni un determinat tipus[27]
Volatile
Pragma per indicar que un element de memòria pot ser modificat externament i cal llegir-lo a memòria cada vegada evitant optimitzacions.[28]
Atomic
Pragma per forçar la lectura i escriptura de manera atòmica (no interrompible i respectant l'ordre a les CPU's de procés especulatiu(ang: out-of-order CPU))[29]
# un tipus tagged (etiquetat), descrit a la implementació com a registre amb els camps de l'objecte.
# procediments i funcions de la instància quan el primer paràmetre és la instància del tipus definit.
# procediments i funcions estàtiques (de la classe) quan no duen la instància com a primer paràmetre.
Els procediments i funcions a nivell de paquet són heretables (virtuals).
Per definir generadors i altres funcions com a no-heretables cal fer-ho en un submòdul.
packagePersonaistypeObjecteistagged-- ''etiquetat'' (defineix el tipus com a constitutiu de classe)private;-- private: definició opaca dels campsprocedureMètodeDeLaInstància(This: Objecte);-- la instància és el primer paràmetreprocedureMètodeEstàtic(Param: Integer);-- no duu la instància com a primer paràmetrefunctionTo_String(This: Objecte)returnString;-- per a l'exemple a ''herència''-- submòdul packageEinesis-- Generadors i Funcions que no volem que s'heretin han d'estar en un submòdul.functionNou_Persona(...)returnObjecte;endEines;privatetypeObjecteistaggedrecord-- camps de dades del tipus de la classeNom:String(1..10);Gènere:Tipus_Gènere;end record;endPersona;
qualificatiu overriding per redefinir un procediment o funció
per referir-se al mètode homònim de la classe base, cal caracteritzar la instància amb el tipus del pare, mitjançant una conversió de tipus: Tipus_del_pare(This).
withPersona;packageProgramadoristypeObjecteisnewPersona.Objecte-- nou tipus ''Objecte'' derivat de Persona.Objectewithprivate;-- opac, definit a l'àrea privadaoverridingfunctionTo_String(This: Objecte)returnString;typeLlenguatgeis(LLENG_ADA,HASKELL,OCAML);-- ADA és paraula reservadapackageEinesis-- submòdul per a funcions no heretablesfunctionNou_programador(pers: Persona.Objecte;esp: Llenguatge)returnObjecte;endEines;privatetypeObjecteisnewPersona.Objectewith-- objecte derivat del tipus de la superclasserecord-- ampliació del registre de camps Especialitat:Llenguatge;end record;endProgramador;
-- implementaciówithAda.Text_IO;withAda.Strings;packagebodyProgramadorispackagebodyEinesisfunctionNou_programador(pers: Persona.Objecte;esp: Llenguatge)returnObjecteisbeginreturnObjecte'(perswithEspecialitat=>esp);-- extensió de registreend;endEines;packageLlenguatge_IOis newAda.Text_IO.Enumeration_IO(Llenguatge);functionTo_String(This: Objecte)returnStringisstr_Esp:String(1..20);beginLlenguatge_IO.Put(To=>str_Esp,Item=>This.Especialitat);return(Persona.To_String(-- crida al mateix mètode, a la superclassePersona.Objecte(This))-- caracterització a la superclasse&"; Especialitat: "&str_Esp);end;...endProgramador;
Constructors, Destructors i Clonadors
Per fer una gestió fina de la memòria cal que els tipus implementin les classes Controlled o bé Limited_Controlled, que proporcionen mètodes per intervenir en les ops. de lligar un objecte a una variable i en deslligar-lo.
Sobre aquestes classes abstractes s'hi pot implementar, si hom vol, un mecanisme d'alliberament per comptador de referències.[30] Com a l'exemple més avall.
El mòdul Ada.Finalization incorpora les classes abstractes Controlled i Limited_Controlled que ofereixen mètodes cridats automàticament en inicialitzar, en assignar, i en sortir de l'àmbit les variables dels tipus de les classes que se'n derivin. Vegeu refs.[31][32]
Classe Controlled: amb mètodes abstractes Initialize, Adjust i Finalize (cridats respectivament de manera automàtica,
Initialize, cridat en la declaració de variables del tipus quan no s'inicialitzen.
Finalize, cridat en deslligar l'objecte de la variable, perquè, o bé se li ha assignat un altre valor a la variable, o bé la variable surt de l'àmbit.
Adjust, cridat en lligar un objecte a una variable en les assignacions, per quan hi ha punters, poder completar la clonació d'una estructura després de la còpia superficial (bit a bit) de la primera ceŀla que el compilador genera.
Classe Limited_Controlled: Inclou Initialize, i Finalize però no Adjust.
En els mètodes Adjust i Finalize s'hi pot implementar un comptador de referències com a l'exemple proposat.
Tipus definits per signatures (Interface)
Des de l'Ada2005.
packageImprimibleistypeObjecteisinterface;procedureImprimeix(This: Objecte)isabstract;-- is abstract => cal implementar-lo en classes derivades.procedureUnAltreMètode(This: Objecte)isnull;-- is null => buit, no requereix implem. en classes derivades.endImprimible;
withProgramador;withImprimible;packageProgramadorAmbImprimibleistypeObjecteisnewProgramador.Objecte-- derivat de Programador.ObjecteandImprimible.Objecte-- i també de Imprimible.Objectewithprivate;procedureImprimeix(This: Objecte);-- redefineix el procediment virtual (abstracte a Imprimible)private-- declaració privadaendProgramadorAmbImprimible;packagebodyProgramadorAmbImprimibleisprocedureImprimeix(This: Objecte)is-- implementa Imprimible begin...end;endProgramadorAmbImprimible;
Concurrència
Fils d'execució:
La clàusula task designa un fil d'execució que engega tot just en acabar d'inicialitzar la construcció que l'enclou. (exemple).
La seva definició inclourà els canals d'entrada (Entry) del fil d'execució.
Exclusió mútua i espera condicionada (POSIX condition variables): La construcció Protected incorpora un monitor a l'estructura. (exemple)
Transferència de control asíncrona: La clàusula select {esdeveniment} then-abort procediment pot incloure un procediment que es cancel·larà en el moment que s'esdevingui algun dels esdeveniments especificats al select.(exemple)[33]
Compilació
Compilació: compila l'arbre de paquets obtingut de les clàusules d'importació with Nom_Paquet;
gnatmakehola.adb
Compilació separada:
gcc-chola.adb
gnatbindhola# genera b~hola.ads i .adb que conté el ''package ada_main'' autogenerat de l'aplicació.
gnatlinkhola
Fitxer de configuració del projecte
El fitxer gnat.adc es pot establir per contenir Pragmes de Configuració del projecte del directori.[34] El compilador cercarà el fitxer de configuració al directori de treball.
L'ordre d'inicialització dels mòduls
El mòdul autogenerat ada_main inclou els procediments d'inicialització adainit i de tancament adafinal. El procediment adainit executa la inicialització de cada mòdul en l'ordre deduït de les clàusules with i les pragmes Elaborate.
gnatbind: genera els fitxers .ads i .adb que conté el mòdul ada_main, amb nom de fitxer obtingut prefixant amb b~ el nom del mòdul principal.
L'ordre d'inicialització es pot alterar quan a un mòdul li convé que un altre s'inicialitzi abans, especificant-ho amb la pragma Elaborate o Elaborate_All.[35]
-- força la inicialització prèvia del mòdul_M i els mòduls que importi.-- alterant l'ordre d'exec. de les inicialitzacions al procés autogenerat ''adainit''PragmaElaborate_All(mòdul_M)
Generació de biblioteques
En cas de voler generar una biblioteca en comptes d'un executable, caldrà fer un programa principal de pega que cridi a les rutines de la biblioteca i extreure'n del mòdul principal generat (ada_main) els processos d'inicialització i tancament adainit i adafinal que inclourem a les rutines d'inicialització i finalització de la biblioteca de relligat dinàmic (.dll o bé .so), nom_biblioinit i nom_bibliofinal.[36]
AdaCore, mantenidor del compilador GNAT, disposa a la pàgina de descàrregues de codi obert d'una versió per a "jvm-windows"[37][38] que també funciona sobre Linux mitjançant l'emulador Wine excepte pels caràcters no anglosaxons (la codif. de caràcters és Latin-1 a Windows i UTF-8 a GNU/Linux).
La biblio paramètrica en tipus i operacions (funció d'un tipus T i d'una op. formal Producte) :
-- fitxer la_meva_biblio.ads -- signaturagenerictypeTisprivate;-- paràmetre de tipus (''private'': tipus opac)withfunctionProducte(X,Y:T)returnT;-- paràmetre funció-- el param. actual ha de coincidir en la signatura de la funciópackageLa_Meva_BiblioisfunctionQuadrat(x:T)returnT;endLa_Meva_Biblio;
-- fitxer la_meva_biblio.adb -- implementaciópackagebodyLa_Meva_Bibliois-- implementa Quadrat basat en la funció Producte que és paràmetre del genèricfunctionQuadrat(x:T)returnTisbeginreturnProducte(x,x);endquadrat;endLa_Meva_Biblio;
Un Functor (mòdul amb un mòdul abstracte com a paràmetre formal). Transformarà instàncies que implementin La_Meva_Biblio.
-- fitxer el_meu_functor.ads -- signaturawithLa_Meva_Biblio;genericwithpackageBiblioisnewLa_Meva_Biblio(<>);-- mòdul formal. cal que el mòdul paràmetre actual n'implementi la signatura-- en aquest cas, cal que sigui derivat de La_Meva_Biblio-- <>: indefinit en la parametrització (abstracte)packageEl_meu_functorisuseBiblio;-- incorpora l'espai de noms del mòdul formalfunctionCub(x: T)returnT;functionQuadrat(x: T)returnTrenamesBiblio.quadrat;-- publica una funció del mòdul formalendEl_meu_functor;
-- fitxer principal.adb-- paquets per relligar amb el ''linker''withLa_Meva_Biblio;withEl_Meu_Functor;withAda.Text_IO;procedurePrincipalis-- nom curt per al mòdulpackageTextIOrenamesAda.Text_IO;-- instanciem mòduls genèrics per a l'entrada/sortida dels tipus primitius per als tipus concretspackageIntIOis newAda.Text_IO.Integer_IO(Integer);-- Integer_IO per a precisió IntegerpackageLFloatIOis newAda.Text_IO.Float_IO(Long_Float);-- Float_IO per a precisió Long_FloatpackageBoolIOis newAda.Text_IO.Enumeration_IO(Boolean);-- Enumeration_IO per al cas Boolean-- instanciem bibliotequespackageLa_Meva_Biblio_sobre_Sencersis newLa_Meva_Biblio(T=> Integer,Producte=> "*");packageLa_Meva_Biblio_sobre_Realsis newLa_Meva_Biblio(T=> Long_Float,Producte=> "*");packageEl_Meu_Functor_sobre_Sencersis newEl_Meu_Functor(La_Meva_Biblio_sobre_Sencers);packageEl_Meu_Functor_sobre_Realsis newEl_Meu_Functor(La_Meva_Biblio_sobre_Reals);-- declaració variablesi:constantInteger:=2;j,k:Integer;x:constantLong_Float:=2.0;y,z:Long_Float;comprovacio:Boolean;beginj:=La_Meva_Biblio_sobre_Sencers.Quadrat(i);y:=La_Meva_Biblio_sobre_Reals.Quadrat(x);k:=El_Meu_Functor_sobre_Sencers.Cub(i);z:=El_Meu_Functor_sobre_Reals.Cub(x);TextIO.Put("Quadrat i Cub de 2 Integer, i comprovació:");IntIO.Put(j,Width=>4);-- format: %4dIntIO.Put(k,4);comprovacio:=j=El_Meu_Functor_sobre_Sencers.Quadrat(i);TextIO.Put(" ");BoolIO.Put(comprovacio);TextIO.New_Line(Spacing=>2);-- spacing: nombre de salts de líniaTextIO.Put("Quadrat i Cub de 2.0 Long_Float, i comprovació:");LFloatIO.Put(y,Fore=>3,Aft=>2,Exp=>0);-- format: %3.2f; Exp (dígits exponent)LFloatIO.Put(z,3,2,0);comprovacio:=y=El_Meu_Functor_sobre_Reals.Quadrat(x);TextIO.Put(" ");BoolIO.Put(comprovacio);TextIO.New_Line;endPrincipal;
Compila i executa:
gnatmakeprincipal.adb
./principal
dona el resultat:
Quadrat i Cub de 2 Integer, i comprovació: 4 8 TRUE
Quadrat i Cub de 2.0 Long_Float, i comprovació: 4.00 8.00 TRUE
Composició en O.O. - Parametritzant per tipus d'objecte
Parametritzant per tipus d'objecte amb requeriments de superclasse i interfaces
-- fitxer imprimible.ads -- només signaturapackageImprimibleistypeObjecteisinterface;procedureImprimeix(obj: Objecte)isabstract;-- is abstract => cal redefinir-lo en la classe derivada-- procedure Imprimeix(obj: Objecte) is null; -- is null => no implementat, no és obligat redefinir-loendImprimible;
La biblio paramètrica en un tipus descendent d'un tipus d'objecte i amb requeriment d'interface
-- fitxer la_meva_biblio.ads -- signaturawithPersona;withImprimible;generictypeTisnewPersona.ObjecteandImprimible.Objectewithprivate;-- tipus formal -- (cal que sigui derivat de Persona.Objecte -- i que implementi Imprimible.Objecte)packageLa_Meva_BiblioisprocedureImprimeixISaltaLinia(obj:T);endLa_Meva_Biblio;
-- fitxer la_meva_biblio.adb -- implementaciówithAda.Text_IO;withAda.Text_IO.Bounded_IO;withAda.Strings;withAda.Strings.Bounded;packagebodyLa_Meva_BiblioisMAX_BUF:constantInteger:=20;packageSB_Bufis newAda.Strings.Bounded.Generic_Bounded_Length(MAX_BUF);packageSB_Buf_IOis newAda.Text_IO.Bounded_IO(SB_Buf);packageTextIOrenamesAda.Text_IO;títol:SB_Buf.Bounded_String;procedureImprimeixISaltaLinia(obj:T)isbeginSB_Buf_IO.Put(títol);Imprimeix(obj);TextIO.New_Line(Spacing=>1);endImprimeixISaltaLinia;begin-- inicialització de mòdul-- útil per inicialitzacions que depenen d'un altre mòdultítol:=SB_Buf.To_Bounded_String(Definicions.TITOL_APLICACIO&": ");endLa_Meva_Biblio;
La classe arrel Persona (incorpora un constructor i un mètode Put_To_String(obj))
-- fitxer persona.ads -- signaturawithAda.Strings.Bounded;-- cadenes de text acotadespackagePersonaistypeObjecteistaggedprivate;-- ''tagged'': objectes, ''private'': opac, definit a l'àrea privadafunctionPut_To_String(obj: Objecte)returnString;packageEinesis-- mòdul niuat per a les funcions que no volem virtuals (heretables)functionNou_Persona(nom: String;edat: Integer)returnObjecte;endEines;MAX_NOM:constantinteger:=16;packageSB_Nomis newAda.Strings.Bounded.Generic_Bounded_Length(MAX_NOM);privatetypeObjecteistaggedrecordNom:SB_Nom.Bounded_String;Edat:Integer;end record;endPersona;
-- fitxer persona.adb -- implementaciówithAda.Text_IO;withAda.Strings;withAda.Strings.Fixed;withAda.Strings.Bounded;packagebodyPersonaispackageIntIOis newAda.Text_IO.Integer_IO(Integer);packagebodyEinesis-- mòdul niuat per les funcions que no volem virtuals (heretables)functionNou_Persona(nom: String;edat: Integer)returnObjecteisbeginreturnPersona.Objecte'(Nom=>Persona.SB_Nom.To_Bounded_String(nom),Edat=>edat);exceptionwhenE:Ada.Strings.Length_Error=>Ada.Text_IO.Put("error: nom massa llarg, màxim: ");IntIO.Put(MAX_NOM);Ada.Text_IO.New_Line(1);raise;endNou_Persona;endEines;-----------------------functionPut_To_String(obj: Objecte)returnStringisMAX_BUF:constantInteger:=40;packageSB_Bufis newAda.Strings.Bounded.Generic_Bounded_Length(MAX_BUF);sb_buf1:SB_Buf.Bounded_String;buf2:String(1..10);useSB_Buf;-- incorpora espai de nomsuseAda.Strings;beginsb_buf1:=To_Bounded_String(SB_Nom.To_String(obj.nom));IntIO.Put(To=>buf2,Item=>obj.edat);returnTo_String(sb_buf1&" "&Fixed.Trim(buf2,Left));endPut_To_String;endPersona;
La classe derivada Programador: implementa l'interface i, a banda, incorpora un constructor i sobrescriu el mètode Put_To_String(obj).
-- fitxer programador.ads -- signaturawithPersona;withImprimible;packageProgramadoristypeObjecteisnewPersona.Objecte-- deriva de Persona.Objecte andImprimible.Objecte-- i també de Imprimible.Objectewithprivate;-- extensió de camps opaca (a l'àrea privada)overridingfunctionPut_To_String(obj: Objecte)returnString;-- sobrescriu mètode de la superclasseprocedureImprimeix(obj: Objecte);typeLlenguatgeis(LLENG_ADA,HASKELL,OCAML,SCALA);-- LLENG_ADA doncs ADA és nom reservatpackageEinesis-- mòdul niuat per les funcions que no volem virtuals (heretables)functionNou_Programador(nom: String;edat: Integer;especialitat: Llenguatge)returnObjecte;endEines;privatetypeObjecteisnewPersona.ObjecteandImprimible.Objectewithrecord-- extensió de registre de campsEspecialitat:Llenguatge;end record;endProgramador;
-- fitxer programador.adb -- implementaciówithAda.Text_IO;withAda.Strings;withAda.Strings.Bounded;packagebodyProgramadorispackagebodyEinesis-- mòdul niuat per les funcions que no volem virtuals (heretables)functionNou_Programador(nom: String;edat: Integer;especialitat: Llenguatge)returnObjecteisbeginreturnObjecte'(Persona.Eines.Nou_Persona(nom,edat)withEspecialitat=>especialitat);endNou_Programador;endEines;------------functionPut_To_String(obj: Objecte)returnStringispackageLlenguatge_IOis newAda.Text_IO.Enumeration_IO(Llenguatge);MAX_BUF:constantInteger:=60;packageSB_Bufis newAda.Strings.Bounded.Generic_Bounded_Length(MAX_BUF);sb_buf1:SB_Buf.Bounded_String;buf2:String(1..12);useSB_Buf;-- incorpora espai de nomsbeginsb_buf1:=To_Bounded_String(Persona.Put_To_String(-- crida al mètode homònim de la superclassePersona.Objecte(obj)-- cal fer un ''up-cast'' (caracterització) de l'objecte -- al supertipus corresp. al mètode));Llenguatge_IO.Put(buf2,obj.especialitat);returnTo_String(sb_buf1&" "&buf2);endPut_To_String;------------procedureImprimeix(obj: Objecte)ispackageTextIOrenamesAda.Text_IO;beginTextIO.Put("Programador: ");TextIO.Put(Put_To_String(obj));endImprimeix;endProgramador;
Principal:
-- fitxer principal.adbwithLa_Meva_Biblio;withProgramador;procedurePrincipalispackageLa_Meva_Biblio_ProgImpis newLa_Meva_Biblio(T=> Programador.Objecte);obj:Programador.Objecte;useProgramador;-- incorpora espai de noms del mòduluseLa_Meva_Biblio_ProgImp;beginobj:=Eines.Nou_Programador("Gabriel",59,Especialitat=>HASKELL);ImprimeixISaltaLinia(obj);endPrincipal;
-- fitxer prova.adbwithAda.Strings;withAda.Strings.Fixed;withAda.Strings.Bounded;withAda.Text_IO;withAda.Text_IO.Bounded_IO;procedureProvaispackageTextIOrenamesAda.Text_IO;str1:String:="abcdefghi";MAX_BUF:constantInteger:=str1'Last;packageSB_Bufis newAda.Strings.Bounded.Generic_Bounded_Length(MAX_BUF);packageSB_Buf_IOis newAda.Text_IO.Bounded_IO(SB_Buf);sb_buf2:SB_Buf.Bounded_String;typeT_ESTATisrange1..(MAX_BUF+1);taskAutomatais-- task és fil d'execució (''thread'')entryLlegeix(ch: inCharacter);-- canal d'entradaentryImprimeix;-- canal d'entradaendAutomata;taskbodyAutomatais-- l'activació s'inicia en completar la inicialització de l'objecte que l'enclouEstat:T_ESTAT:=T_ESTAT'First;-- use SB_Buf ;beginloopselectwhenEstat<T_ESTAT'Last=>acceptLlegeix(ch:inCharacter)doSB_Buf.Append(sb_buf2,ch);TextIO.Put(ch);-- fem l'eco endLlegeix;Estat:=Estat+1;orwhenEstat=T_ESTAT'Last=>acceptImprimeixdoTextIO.New_Line;SB_Buf_IO.Put(sb_buf2);endImprimeix;orterminate;-- acaba quan hi ha una opció ''terminate'' oberta-- i no hi ha entrades pendents -- i totes les tasques (fils d'execució) estan igual -- i el procés principal enllesteix.-- o bé, en comptes d'acabar, especificar un lapse de temps i les accions a prendredelay1.0;TextIO.New_Line-- termini i accions subseqüents al vencimentendselect;endloop;endAutomata;beginforiinstr1'RangeloopAutomata.Llegeix(str1(i));delay0.2;endloop;Automata.Imprimeix;endprova;
gnatmakeprova.adb
./prova
Transferència de control asíncrona
Càlculs abortables per venciment de terminis o altres esdeveniments esmentats a la clàusula select. Detalls a la documentació.[42]
select-- ''delay or triggering statement''delay5.0;Put_Line("El càlcul no convergeix");thenabort-- Aquest càlcul està limitat en temps pel termini prèviament esmentatCàlcul_que_pot_excedir_el_temps_tolerable(X,Y);endselect;
protected - Exclusió mútua i accés condicionat
La construcció protected aporta coherència al manteniment d'estructures compartides per diferents fils d'execució.
Aporta un monitor a l'estructura per garantir l'exclusió mútua dels fils d'execució que executin els membres exportats de l'estructura.[43]
Les clàusules Entry permeten condicionar el desblocatge d'execució (monitor) a una condició expressada en la clàusula when.
-- fitxer prova.adb -- procés cua d'esdevenimentswithAda.Text_IO;withAda.Containers.Doubly_Linked_Lists;procedureProvaispackageTextIOrenamesAda.Text_IO;typeTEsdevenimentis(SUCCES_A,SUCCES_B,FINAL);packageTEsdeveniment_IOis newAda.Text_IO.Enumeration_IO(TEsdeveniment);packageCua_Esdevis newAda.Containers.Doubly_Linked_Lists(TEsdeveniment);-- cua de dos caps, il·limitada----------------protectedCua_ProtegidaisprocedureAfegir(Esdev: TEsdeveniment);-- procedure (no bloca) (cua és il·limitada) entryRetirar_Primer(Esdev: outTEsdeveniment);-- entry (pot blocar) (Retirar_Primer requereix cua no buida)privateCua:Cua_Esdev.List;endCua_Protegida;protectedbodyCua_ProtegidaisprocedureAfegir(Esdev: TEsdeveniment)isbeginCua_Esdev.Append(Cua,Esdev);endAfegir;entryRetirar_Primer(Esdev: outTEsdeveniment)-- canal d'entrada whennotCua_Esdev.Is_Empty(Cua)is-- requeriment d'accésbeginEsdev:=Cua_Esdev.First_Element(Cua);Cua_Esdev.Delete_First(Cua);endRetirar_Primer;endCua_Protegida;----------------taskProcessa_Esdeveniments;-- no exporta restaskbodyProcessa_EsdevenimentsisEs_Final:Boolean:=False;beginwhilenotEs_FinalloopdeclareEsdev:TEsdeveniment;beginCua_Protegida.Retirar_Primer(Esdev);TEsdeveniment_IO.Put(Esdev);TextIO.New_Line;Es_Final:=Esdev=FINAL;end;endloop;endProcessa_Esdeveniments;beginCua_Protegida.Afegir(SUCCES_A);Cua_Protegida.Afegir(SUCCES_B);delay1.0;Cua_Protegida.Afegir(FINAL);endProva;
-- fitxer prova_mem.adbwithAda.Text_IO;withAda.Unchecked_Deallocation;withSystem.Pool_Local;withAda.Exceptions;packagebodyProva_MemispackageExceptrenamesAda.Exceptions;packageTxt_IOrenamesAda.Text_IO;packageInt_IOis newAda.Text_IO.Integer_IO(Integer);packageBoolean_IOis newAda.Text_IO.Enumeration_IO(Boolean);procedureProvaistypeTipusisarray(1..1000)ofInteger;typePtr_A_TipusisaccessTipus;Local_Pool:System.Pool_Local.Unbounded_Reclaim_Pool;-- memòria d'àmbit.forPtr_A_Tipus'Storage_PooluseLocal_Pool;procedureFree_Ptr_A_TipusisnewAda.Unchecked_Deallocation(Tipus,Ptr_A_Tipus);subtypePtr_No_Nul_A_TipusisnotnullPtr_A_Tipus;A:Ptr_A_Tipus;procedureAllotjaisbeginA:=newTipus'(others=>10);-- allotja i inicialitzaendAllotja;procedureDesAllotjaisbeginFree_Ptr_A_Tipus(A);endDesAllotja;procedureComprova_Nul(B: Ptr_A_Tipus)isbeginTxt_IO.Put("Que és nul el punter? ");Boolean_IO.Put(B=null);Txt_IO.New_Line;endComprova_Nul;procedureImprimeix_Elem(B: Ptr_No_Nul_A_Tipus)is-- restringit pel subtipus, dispara exc. Constraint_Error-- procedure Imprimeix_Elem (B: not null access Tipus) is -- alternativavec:Tipus;beginvec:=B.all;Txt_IO.Put("El primer elem. és");Int_IO.Put(vec(1),Width=>4);Txt_IO.New_Line;endImprimeix_Elem;beginAllotja;A.all:=(others=>20);Comprova_Nul(A);Imprimeix_Elem(A);Allotja;DesAllotja;-- A queda ''null''Comprova_Nul(A);beginImprimeix_Elem(A);exceptionwhenConstraint_Error=>Txt_IO.Put_Line("Restricció ''not null'' fallida: El punter era nul");whenE:others=>Txt_IO.Put_Line("disparada: "&Except.Exception_Name(E));end;Allotja;endProva;-- el Local_Pool queda fora d'àmbit i se'n reclama la memòriaendProva_Mem;
O.O. - Finalització controlada - Estructura amb component allotjat dinàmicament i comptador de referències
Classe d'objectes amb Finalització controlada, derivats de la classe abstracta Ada.Finalization.Controlled. Mètodes cridats automàticament:
Initialize: cridat en les declaracions sense inicialització
Finalize: cridat en deslligar l'objecte de la variable, perquè, o bé se li ha assignat un altre valor a la variable, o bé la variable surt de l'àmbit
Adjust: cridat en lligar un objecte a una variable a les assignacions, després de la còpia superficial (bit a bit) de l'objecte, per si cal clonar els membres referits per punters o si cal portar un comptador de referències.
-- fitxer controlat.adswithCarrega;withAda.Finalization;packageControlatisuseCarrega;typeObjecteisnewAda.Finalization.Controlledwith-- classe derivada de ''Ada.Finalization.Controlled''recordPtr_A_La_Meva_Carrega:Carrega.Ptr_A_Carrega:=null;end record;privateprocedureInitialize(Obj: inoutObjecte);-- constructor buit (cridat quan no hi ha inicialització en la declaració)procedureAdjust(Obj: inoutObjecte);-- constructor de còpia (ajustatge després de còpia superficial)procedureFinalize(Obj: inoutObjecte);-- cridat en sortir de l'àmbit o quan l'obj. es deslliga de la variable quan és modificadaendControlat;
-- fitxer controlat.adbwithAda.Text_IO;packagebodyControlatispackageTxt_IOrenamesAda.Text_IO;packageInt_IOis newAda.Text_IO.Integer_IO(Integer);procedureInitialize(Obj: inoutObjecte)is-- constructor buit beginTxt_IO.Put("Initialize:");Obj.Ptr_A_La_Meva_Carrega:=Carrega.Nova_Carrega(Id=>1);Txt_IO.New_Line;end;procedureAdjust(Obj: inoutObjecte)is-- constructor de còpia (ajustatge després de còpia superficial bit a bit)beginTxt_IO.Put("Adjust :");Carrega.Incr_Refs(Obj.Ptr_A_La_Meva_Carrega);Txt_IO.New_Line;end;procedureFinalize(Obj: inoutObjecte)is-- en sortir de l'àmbit o en ésser deslligat de la ref.refs:Natural;beginTxt_IO.Put("Finalize :");ifnotCarrega.Es_Nul(Obj.Ptr_A_La_Meva_Carrega)thenCarrega.Decr_Refs(Obj.Ptr_A_La_Meva_Carrega,refs);ifrefs=0thenCarrega.Allibera_Carrega(Obj.Ptr_A_La_Meva_Carrega);Txt_IO.Put("; Desallotjat");endif;endif;Txt_IO.New_Line;end;endControlat;
-- fitxer principal.adbwithCarrega;withControlat;withAda.Finalization;withAda.Text_IO;procedurePrincipalispackageTxt_IOrenamesAda.Text_IO;useControlat;obj1:Controlat.Objecte;-- Sense inicialitzar, ''Initialize'' s'executabegindeclare-- àmbit intern fet a posta per a l'exempleobj2:Controlat.Objecte:=(Ada.Finalization.ControlledwithPtr_A_La_Meva_Carrega=>Carrega.Nova_Carrega(Id=>2));-- ''Initialize'' no actúaobj3:Controlat.Objecte:=(Ada.Finalization.ControlledwithPtr_A_La_Meva_Carrega=>Carrega.Nova_Carrega(Id=>3));-- ''Initialize'' no actúabeginTxt_IO.New_Line;Txt_IO.Put_Line("-- obj2 := obj3 -- finalitza objecte de la var obj2; adjust objecte de la var obj3");obj2:=obj3;Txt_IO.New_Line;Txt_IO.Put_Line("-- sortida àmbit intern, variables obj2 i obj3 surten del seu àmbit");end;-- sortida de l'àmbit, Txt_IO.New_Line;Txt_IO.Put_Line("-- sortida àmbit extern, variable obj1 surt de l'àmbit");endPrincipal;
Compila i executa:
gnatmakeprincipal.adb
./principal
dona:
Initialize: Càrrega Id.: 1 Refs: 1
Càrrega Id.: 2 Refs: 1
Càrrega Id.: 3 Refs: 1
-- obj2 := obj3 -- finalitza objecte de la var obj2; adjust objecte de la var obj3
Finalize : Càrrega Id.: 2 Refs: 0; Desallotjat
Adjust : Càrrega Id.: 3 Refs: 2
-- sortida àmbit intern, variables obj2 i obj3 surten del seu àmbit
Finalize : Càrrega Id.: 3 Refs: 1
Finalize : Càrrega Id.: 3 Refs: 0; Desallotjat
-- sortida àmbit extern, variable obj1 surt de l'àmbit
Finalize : Càrrega Id.: 1 Refs: 0; Desallotjat