You are on page 1of 29

CAP. 1 INTRODUO 1.1. Histria Originrio do departamento de defesa dos USA, para a rea de aplicaes de sistema embebidas.

. Comeou em 1974. Em 1983 culmina com a edio do ANSI Satndard for Ada. Uma revio comeou em 1988. Tem grandes preocupaes com a portabilidade, de modo a dar em todas as arquitecturas. Em 1995, Ada 95 compreende uma linguagem Core mais um pequeno n de Anexos especializados. 1.2. ENGENHARIA DE SOFTWARE No se deve pensar que o Ada apenas mais uma linguagem de programao. Ada acerca de Engenharia de Software. H 2 problemas maiors com o desenvolvimento do software: a necessidade de reutilizao de componentes de software e a necessidade de se estabelecerem modos disciplinados de trabalhar. O Ada fivel. A tipagem forte e caractersticas relacionadas asseguram que os programas tenham poucas surpresas. reduz os custos e riscos do desenvolvimento de software. Adiciona flexibilidade extra, por ex. com os tipos tagged extendidos, a facilidade da livraria hierrquica, e a grande habilidade para manipular ponteiro e referncias. Como consequncia, Ada 95 incorpora os benefcios das linguagens OO sem incorrer nas penetrantes sobrecargas de outras linguagens tais como o Smalltalk ou a insegurana trazida pela bas do C, no caso do C++. Uma outra inovao so os tipos protegidos para o modelo de tarefas. Isso permite uma mais natural e eficiente implementao de paradigams standard de acesso a dados partilhados. Isto beneficia a velocidade fornecendo primitivas de baixo nvel como os semforos. mais, a viso claramente orientda aos dados pelos tipos protegidos, casa naturalmente com o esprito do paradigam OO. Dois tipos de aplicao so muito sensveis ao Ada os muito grandes e os meuito crticos. Os primeiros exigem uma cooperao de vrios elementos em equipa e a inegridade crtica e mantida atravs da compilao. As mudanas de requisitos tambm so bem recebidas pelo Ada 95. A flexibilidade completa do Ada no apropriada para os sistemas crticos, mas a fiabilidade intrnseca do kernel fortemente tipado exactamente o que requerido. 1.3. EVOLUO E ABSTRACO Cada avano parece estar associado com a introduo de um nvel de abstraco que remove detalhes desnecessrios e nocivos do programa. No incio dos 50s o Fortran introduziu a abstraco de expresses, o que permitiu expresses do tipo : X = A + B(I), e ento o uso de registos mquina para avaliar a expresso foi completamente escondido do programador. O 2 avano diz respeito abstraco de controlo, com o algol 60; o fluxo de controlo estruturado e pontos de controlo individuais no tm de ser numerados ou nomeados: if X = Y then P:=Q else A:0B e o compilador gera os goto e etiquetas. O 3 avano foi a abstraco de dados. Isto significa separar os detalhes da representao dos dos dados das operaes abstractas definidas sobre os dados. O Pascal introduziu uma certa quantidade de abstraco de dados como os tipos enumerados. Uma outra forma de abstraco de dados tem a ver com a visibilidade. O Ada foi, provavvelmente, a primeira linguagem prtica a juntar todoas estas abstraces de dados. o Simula tambm foi importante niosto, com o seu conceito de classe. No h definio precisa de OOP, mas a sua essncia uma forma flexvel de abstraco de dados fornecendo a cpacidade de definir novas abstraces de dados em termos de antigos e permitindo seleco dinmica de tipos. todos os tipos no Ada 83 so estticos -> OBL. Contudo, o Ada 95 inclui as funcionalidades essenciais associadas com o OOP, tais como extenso de tipos e polimorfismo dinmico. Resta saber como o Ada 95 fornece o que chamamos de abstraco de objectos CAP. 2 CONCEITOS SIMPLES 2.1. Metas Chave Ada uma linguagem grande. Algumas das caractersticas do Ada so: - Legibilidade - Tipagem Forte isto assegura que cada objecto tem um claramente definido conjunto de valores que pode tomar e previne confuso entre conceitos logicamente diferentes. Como consequncia

muitos erros so detectados pelo compilador o qual em outra slinguagens (como o C) pode conduzir a um executvel mas programa incorrecto. - Programao em Progaramas Grandes encapsulao, compilao separada, gesto de biblioteca so necessarios para escrever programas grandes e portveis e de fcil manuteno - Gesto de Excepes - Abstraco de Dados - portabilidade e mennutentabilidade extra pode ser conseguida se os detalhes da representao dos dados forem separdos das especificaes das operaes lgicas com os dados. - Programao Orientada a Objectos para reutilizao. Extenso de tipos (herana), polimorfismo e ligao tardia. - Tarefas actividades paralelas - Unidades Genricas em muitos casos a lgica de parte de um programa independente dos tipos de valores a sertem manipulados -> nico template. particularmente til para a construo de livrarias. - Interfaces para comunicar com programas em outras linguagens. 2.2. Estrutura Geral Um objectivo importante da Engenharia de Software a reutilizao de pedaos de programa j existentes, de modo a que o novo cdigo detalhado mantido num mnimo. O conceito de uma biblioteca de componentes de programa emerge naturalmente e um aspecto importante de uma linguagenm de programao pois a sua capacidade de aceder a itens de biblioteca. Um programa de Ada um (sub)programa principal main que chama por servios de outras unidade de biblioteca. O subprograma principal toma a forma de procedimento. As unidade de livraria podem ser subprogramas (procedimento ou funes) mas o mais provvel que sejam pacotes/packages. Um pacote um grupo de itens relacionados tais como subprogramas mas podem conter tambm outras entidades. with Sqrt, Simple_IO; procedure Print_Root is use Simple_IO; X: Float; begin Get(X); Put(Sqrt(X)); end Print_Root; Entre is e begin podemos escrever declaraes, que introduzem entidades que queremos manipular. Um valor associado a X pelo chamar do procedimento get que est no nosso pacote Simple_IO. Escrevendo use Simple_IO, dnos acesso imediato a facilidades no pacote Simple_IO. Se o tivssemos omitido, teramos de escrever Simple_IO.Get(X). H 69 palavras chave. procedure e is so indicadas paraindicar a estrutura do programa. put e x so indicados como identificadores. Para clareza, escreveremos as palavras reservadas em minsculas e bold e usaremos maisculas para iniciais das outras todas. Para toda uma srie de ns e impresses de cada resposta numa linha separada. podemos parar o programa algo arbitrariamente dando-lhe um valor de zero: with Sqrt, Simple_IO; procedure Print_Root is use Simple_IO; X: Float; begin Put(Roots of various numbers); New_Line(2); loop Get(X); exit when X = 0.0; Put(Root of); Put(X); Put(is); if X < 0.0 then Put(not calculabel); else Put(Sqrt(X));

end if; New_Line; end loop; New_Line; Put(Program finished); New_Line; end Print_Roots; os procedimentos New_Line e Put fazem parte do pacote Simple_IO. Ter mais de um subprograma com o mesmo nome o que se chama sobrecarga. ex. Put com strings e com floats. A estrutura geral de parnteses deve ser observada; loop joga com end loop e if com end if. Todas as estruturas de controlo do Ada tem esta forma fechada em vez da forma aberta do Pascal e c que podem conduzir a programas incorrectos e/ou pobremente estruturados. A funo Sqrt ter uma estrutura similar quela do nosso subprograma principal. function sqrt(F:Float) return Float is R:Float; begin -- compute value of Sqrt(F) in R return R; end Sqrt; Vemos aqui a descrio dos parmetros formais (neste caso apenas um) e o tipo do resultado. Os comentrios comeam com um duplo hfen. Note a distino entre uma funo, que retorna um resultado e chamada como parte de uma expresso e um procedimento, que no tem um resultado e chamado por uma instruo. O package Simple_IO ter 2 partes: a especificao que descreve a sua interface ao mundo exterior, e o corpo que contm os detalhes de como ser implementado. Pode ser: package Simple_IO is procedure Get(F. out Float; procedure Put(F: in Float); procedure Put(S: in string); procedure New_Line(N: in Integer :=1); end Simple_IO; O parmetro de Get um out porque o efeito de uma chamada tal como Get(X); transmitir um valor para fora do procedimento para o parmetro actual X. Os outros so in porque o parmetro vai para dentro do procedimento. Se for omitido in por defeito. As funes s podem ter in. Note como o valor por defeito de 1 para o parmetro de New_Line indicado. O corpo do package para a Simple_IO conter os corpos completos dos procedimentos e outro material de suporte implementao e ser algo do tipo: with Ada.Text_IO; package body Simple_IO is; procedure Get(F: out Float) is end Get; -- outros procedimentos similarmente end Simple_IO; A notao indica que Text_IO um pacote filho do pacote Ada. De realar que a ideia dos pacotes uma das mais importantes conceitos em Ada. Um progaram deve ser concebido como um n de componentes que fornecem servios e que recebem servios uns dos outros. O acesso ao pacote Satndard automtico. Exerccio 2.2. pg.16 2.3. O MODELO DOS TIPOS ESCALARES Um dos benefcios chave do Ada a tipagem forte. podemos ilustrar com o tipo enumerado. declare type Colour is (Red, Amber, Green); type Fish is (Cod, Hake, Salmon);

X, Y: Colour; A, B: Fish; begin X:= Red; --ok A:= Hake; --ok B:= X; --illegal end; A regra fundamental da tipagem forte que no podemos associar um valor de um tipo a uma varivel de um tipo diferente. 3 tipos enumerados so predefinidos no pacote Standard. Um o type Boolean is (False, True); que desempenha um papel fundamental no controlo da fluxo: if X < 0.0 then. Os outros so Character e Wide_Caracther. Todos os outros tipos de dados so construdos a partir de tipos enumeriados e tipos numricos. Um dos problemas dos tipos numricos como obter portabilidade e eficincia. conveniente introduzir o conceito de tipo derivado. type Light is new Colour; so logicamente distintos. Podem ser convertidos. declare type Light is new Colour; C: Colour; L: Light; begin L:= Amber; -- a luz amber no a cor C:= L --ilegal C:=Colour(L) --converso explcita ... end; Se escrevermos type My_Float is new Float; ento My_Float ter todas as operaes (+,-,etc.) de Float. Suponha que vai para um computador diferente, onde no h Float mas sim Long_Float. Ento type My_Float is new Long_Float, ser a nica alterao necessria. melhor ainda, podemos definir type My_Float is digits 7; que far com que My_Float seja baseado no mais pequeno tipo definido com pelo menos 7 dgitos. podemos tambm definir type My_Integer is range 1000_000..+1000_000. O ponto de tudo isto que no boa prtica usar tipos numricos predefinidos directamente quando se escrevem programas profissionais que precisem de ser portveis. 2.4. ARRAYS E REGISTOS Os arrays podem ser annimos mas os registos tm sempre um nome de tipo. Como ex. do uso de arrays suponha que queremos computar as sucessivas linhas do Tringulo de Pascal as 10 promeiras linhas. podemos declarar: Pascal: array(0..10) of Integer e agora assumir que os valores correntes do array Pascal correpondem linha n-1, com o componente Pascal(0) sendo 1, ento a prxima linha pode ser calculada num array similar Next: Next(0) := 1; for I in 1 .. N-1 loop Next(I) := Pascal(I-1) + Pascal(I); end loop; Next(N) := 1; e depois o Next poderia ser copiado para o array Pascal. De notar que o array intermdio Next podia ser evitado se iterarmos para trs: Pascal(N) := 1; for I in reverse 1 .. N-1 loop Pascal(I) := Pascal(I-1) + Pascal(I); end loop; Podemos tambm declarar arrays de vrias dimenses: Pascal2: array (0 .. 10, 0 .. 10) of Integer; e ficaramos com:

Pascal2(N,0) := 1; for I in 1 .. N-1 loop Pascal2(N,I) := Pascal2(N-1,I-1) + Pascal2(N-1,I); end loop; Pascal2(N,N) := 1; se quisssemos ter declarado com um nome: type Row is array (0 .. Size) of Integer; Pascal, Next: Row; type String is array (Positive range <>) of character; ilustra uma forma de declarao de tipo que se diz indefinido porque no diz qual a fronteira do array. Isso ter de ser fornecido quando o objecto declarado: A_Buffer: String(1..80); O identificador Positive indica um subtipo do Integer. Um registo um objecto compreendendo um n de componentes com nome, tipicamente de diferentes tipos. type Buffer is record Data: String(1..80); Start, Finish: Integer; end record; um buffer individual pode ento ser declarado por My_Buffer: Buffer; e para manipular My_Buffer.Start := 1; My_Buffer.Finish := 3; My_Buffer.Data(1..3) := XYZ; Pascal(0..4) := (1, 4, 6, 4, 1); My_Buffer := ((X, Y, Z, others => ), 1, 3); Exerccio 2.4. pg.21 2.5. TIPOS DE ACESSO o nome em Ada para tipos ponteiro. Permitem processamento de listas e so usados tipicamente com tipos record. O Ada fornece um elevado grau de fiabilidade e flexibilidade considervel atravs dos tipos de acesso. Os tipos de acesso tm de explicitamente indicar o tipo de dados a que se referem. Vamos restringir-nos quele tipo de dados declarados numa pool de armazenamento 8o termo Ada para heap). Suponhamos que queremos declarar vrios Buffers: type Buffer_Ptr is acess Buffer; Handle: Buffer_Ptr; Handle:= new Buffer; isto aloca um buffer na pool de armazenamento e coloca uma referncia para ele na varivel Handle. Podemos depois referir-nos aos vrios componentes do buffer indirectamente: Handle.Start := 1; Handle.Finish := 3; e podemos referir-nos ao registo completo como Handle:all. Os tipos de acesso so de particular valor para processamento de listas onde uma estrutura de registo contm um valor de acesso a outra estrutura de registo. Ex. classico: type Cell; type Cell_Ptr is acess Cell; type Cell is record Next: Cell_Ptr; Value: Data; end record; 2.6. ERROS E EXCEPES O aparecimento de uma excepo indica que algo de inabitual aconteceu e a sequncia normal de execuo foi quebrada. No nosso caso (raiz quadrada de valor negativo) a excepo pode ser Constraint_error que predefinida e declarada no pacote Standard. Se no pensarmos nesta

hiptese, o programa termina. mas podemos, contudo prever uma excepo e tomar aces de remediao se ela ocorrer. De facto, podemos substituir a instruo condicional por: begin Put(Sqrt(X)); exception when Constraint_Error => Put(not calculable); end; H 4 categorias de erros: - muitos erros so detectados pelo compilador erros de pontuao, viola~oes das refgras de tipos - Outros so detectatdos quando o programa executado diviso por zero -> aparece uma excepo. - O programa quebra as regras da linguagem por ex. um programa no deve usar uma varivel antes de ela ter um valor associado. Nestes caso o comportamento no previsvel e os erros so chamados de fronteira. - em situaes mais extremas , h certos tipos de erros que leval a comportamentos imprevisveis diz-se que o comportameto errneo. Dissmos que o Ada tenta encontrar os erros o mais cedo possvel. type Signal is (Danger, caution, Clear); if The_Signal = Clear then Open_Gates; Start_Train; end if; Os tipos enumerados em C no so fortemente tipados e essencialmente fornecem nomes para constantes inteiras com valores 0, 1 e 2 representando os 3 estados. Isto porencialmente perigoso pois podemos associar o valor 4 enquanto em Ada tal correspondncia no possvel. Se pusermos um ponto e vrgula a mais, o programa em C abre sempre as portas perogoso. Outra possibilidade que o sinal == seja escrito, por engano, =. A igualdade torna-se numa associao e tambm retorna o resultado como o argumento do teste e assim as portas so sempre abertas e o comboio posto em movimento perogoso. Claro que muitos erros no podem ser detectados em tempo de compilao: Index:=81; ... My_Buffer.Data(Index) := x; Tal verificado em run time e aparece uma Constraint_Error. mas o C, sem dvida, escreveria por cima de uma pea adjacente. Podemos declarar: subtype Buffer_Index is Integer range 1..80; Index: Buffer_Index ou Index: Integer range 1..80; e o erro seria detectado mais cedo. 2.7. TERMINOLOGIA Um glossrio de termos est no apndice 2. O termo esttico refer-se a coisas que podem ser determinadas em tempo de compilao. Enquanto o termo dinmico se refere a coisas determinadas durante a execuo. Uma marca algo que no parte do programa mas mais como uma pista, o que feito pelo constructo pragma. pragma Optimize(Space); CAP: 3 type Buffer is record Data: String(1..80); Start: Integer; Finish: Integer; end record; ABSTRACO

Start e Finish indexam as pontas da parte do buffer contendo informao til. A associao e leitura pode ser feita directamente como vimos. Esta ssociao directa pode no ser muito avisada pois o utilizador pode inadvertidamente colocar valores inconsistentes nos componentes ou ler componentes do array sem nexo. Uma muito melhor aproximao criar um Tipo Abstracto de Dados (ADT) e assim o utilizador no pode ver os detalhes internos do tipo mas pode apenas aceder atravs de vrias chamdas a subprogramas que definem um protocolo apropriado. Isto pode ser feito usando um pacote contendo um tipo priovado. Vamos supor que o protocolo nos permite carregar o buffer e l-lo um caracter de cada vez: package Buffer_System is --parte visvel type Buffer is private; procedure Load(B: out Buffer; S: in String); procedure Get(B: in out Buffer; C: out Character); private --parte privada Max: constant Integer:=80; type Buffer is record Data: String(1..Max); Start: Integer := 1; Finish: Integer .= 0; end record; end Buffer_System; package body Buffer_System is procedure Load(B: out Buffer; S: in String) is begin B.Start := 1; B.Finish := Slength; B.Data(B.Start .. B.Finish) := S; end Load; procedure Get(B: in out Buffer; C: out Character) is begin C:= B.Data(B.Start); B.Start := B.Start+1; end Get; end Buffer_System; H pois 2 vises do tipo Buffer: o cliente externo e os subprogramas servidores. O efeito lateral que o utilizador pode declarar e manipular um buffer escrevendo simplesmente: My_Buffer: Buffer; Load(My_Buffer, Some_String); Get(My_Buffer, A_Chracter); H 2 vantagens: uma que o utilizador no pode inadvertidamente empregar mal o buffer e a 2 que a estrutura interna do tipo privado pode ser rearranjada se necessrio e,desde que o protocolo seja mantido, o programa utilizador no precisa ser alterado. O design de protocolos de interface a chave do desenvolveimento e posterior manuteno de programas grandes. Error: exception if SLenght > Max or B.Start <= B.Finish then raise Error; end if; H uma excepo se houver uma tentativa de escrever em ciam de dados ou a string for muito grande. Get marcada com in e out porque o procedimento l o valor inicial do Buffer e actualiza-o. Exerccio 3.1. pg.29 3.2. OBJECTOS E HERANA

O utilizador externo no pode ver os componentes mas pode apenas manipular o buffer atravs de vrios subprogramas associados com o tipo. As operaes primitivas (subprogramas declarados com o tipo privado e o prprio tipo) so chamados mtodos em algumas linguagens. Outras ideias importantes no OOP so: - A capacidade de definir um tipo em termos de outro e especialmente como uma extenso de um outro; isto extenso de tipos. - A capacidade de esse tipo derivado de herdar as operaes primitivas do seu pai e tambm adicionar e substituir tais operaes; isto herana. - A capacidade de distinguir o tipo especfico de um objecto em run time entre vrios tipos relacionados e em particular seleccionar uma operao de acordo com o tipo especfico; isto polimorfismo (dinmico). A forma mais natural de tipo para os propsitos de extenso claro o registo onde podemos considerar a extenso como uma simples adio de componentes. O outro ponto que se ns precisarmos de distinguir o tipo em run time ento o objecto tem de conter uma indicao do seu tipo. Isto fornecido por um componente escondido chamado tag. type Object is tagged record X_Coord: Float; Y_Coord: Float; end record; a palavra reservada tagged indica que os valores do tipo carregam uma tag em tempo de execuo e que o tipo pode ser extendido. type Circle is new Object with record Radius: Float; end record; se no quisermos adicionar componentes: type Point is new Object with null record; Isto significa que sempre claro numa delarao se o tipo tagged ou no desde que contenha ambos tagged e with se o for. As operaes primitivas de um tipo so aquelas declaradas na mesma especificao de pacote do tipo e que tm parmetros ou resultados do tipo. Na derivao estas operaes so herdadas. Podem ser sobrecarregadas e novas operaes podem ser adicionadas. function Distance(O: in Object) return Float is begin return Sqrt(O.X_Coord**2 + O.Y_Coord**2); end Distance; function Area(O: in Object) return Float is begin return 0.0; end Area; function Area(C: in Circle) return Float is begin return Pi * C.Radius**2; end Area; que sobrecarrega. podemos resumir estas ideias dizendo que a especificao sempre herdada enquanto a implementao pode ser herdada mas pode ser substituda. Um tipo derivado deve ser declarado no mesmo pacote do seu pai. package Geometry is type Object is tagged ...; function Distance(O: in Object) return Float; function Area(O: in Object) return Float; type Circle is new Object with ; function Area(C: in Circle) return Float; type Point is new Object with null record; end Geometry;

package body Geometry is --corpos da funo Distance e das 2 funes Area end Geometry; para converter: O: Object := (1.0, 0.5); C: Circle := (0.0, 0.0, 43.7); O := Object(C); C:= (O with 41.2); Concluimos dizendo que um tipo privado pode tambm ser tagged type Shape is tagged private; Se quisermos que o tipo Shape seja derivado de Objecto e mantenha os componentes adicionais escondidos: with Geometry; package Hidden_Shape is type Shape is new Geometry.Object with private; --viso do cliente private type Shape is new Geometry.Object with --viso doservidor record -- os componentes privados end record; end Hidden_Shape; Exerccio 3.2 pg. 34 3.3. CLASSES E POLIMORFISMO Contudo, muito importante notar que uma operao no pode ser tirada enm um componete pode ser removido. Desde que tm estas propriedades comuns natural que devemos ser capazes de manipular um valor de qualquer tipo na hierarquia sem saber exactamente que tipo , desde que usemos apenas as propriedades comuns. Esta manipulao feita atravs do conceito de classe. Um conjunto de tipos como os que vimos uma classe. Associado com cada classe est um tipo chamado a class wide type, que para o conjunto com raiz em Object ObjectClass. function Moment(OC: ObjectClass) return Float is begin return OC.X_Coord * Area(OC); end Moment; Esta funo tem um parmetro formal da CWT ObjectClass. Isto significa que pode ser chamada com um parmetro actual cujo tipo seja um qualquer tipo especfico da classe, compreendendo o conjunto de todos os tipos derivados de Object. Assim, podemos escrever: C: Circle... M: Float; M:=Moment( C ); Note que a funo particular Area a ser chamada no conhecida at execuo. A escolha depende do tipo especfico do parmetro e isso determinado pela tag. Esta seleco conhecida co o despacho e um aspecto vital do comportamento dinmico fornecido pelo polimorfismo. O que acontece se: function Moment(O: Object) return Float is begin return O.X_Coord * Area(O); end Moment; Isto retirna sempre zero porque a funo Area para um Object retorna sempre zero. Podemos claro sobrecarregar: function Moment(C: Circle) return Float is begin return C.X_Coord * Area(C); end Moment;

Mas isto tedioso pois requer duplicao desnecessria de cdigo. Uma maior vantagem de usar operaes em class wide tal como Moment que um sistema usando-o pode ser sobrecarregado, compilado e tstado sem saber todos os tipos especficos a que ser aplicado. mais, podemos ento adicionar mais tipos ao sistema sem recompilao. Isto cria uma interface flexvel e xtensvel ideal para construir um sistema a partir de componentes reutilizveis. Uma dificuladade com a flexibilidade fornecida pelas CWT que no podemos saber que espao vi ser ocupado por um objecto arbitrrio porque o tipo pode ser extendido. Assim, sempre que declaramos um objecto de uma CWT tem de ser inicializado. Uma restrio similar que no podemos ter um array de CW componentes (mesmo que inicializados) porque os componentes podem ser de diferentes tipos especficos e assim de diferentes tamanhos e impossvel de indexar eficientemente. Uma consequncia destas desnecessarias restries que natural usar tipos de acesso com OOP pois no h problema em apontar objectos de diferentes tamanhos em alturas diferentes. type Pointer is acess ObjectClass; type Cell; type Cell_Ptr is acess Cell; type Cell is record Next: Cell_Ptr; Element: Pointer; end record; Podemos agora facilmente processar os objectos da lista e por ex. computar o momento total do conjunto de objectos chamando a funo: function Total_Moment(The_List: Cell_Ptr) return Float is Local: Cell_Ptr:= The_list; Result: Float := 0.0; begin loop if Local = null then --fim da lista return Result; end if; Result := Result + Moment(Local.Element.all); Local := Local.Next; end loop; end Total_Moment; Terminamos considerando os tipos abstractos. por vezes convm declarar um tipo como fundao de uma classe de tipos com certas propriedades comuns mas sem permitir que objectos do tipo original sejam declarados. package Objects is type Object is abstract tagged record X_Coord: Float; Y_Coord: Float; end record; function Distance(O: in Object) return Float; function area(O: in Object) return Float is abstract; end Obejcts; ilegal declarar um objecto de um tipo abstracto e um subprograma abstracto no em corpo e assim no pode ser chamado. Exerccio 3.3. pg. 39 3.4. GENERICIDADE Nesta seco introduziremos o conceito complementar de polimorfismo esttico: a escolha do tipo feita estaticamente em tempo de compilao. O objectivo a reutilizao. Precisamos de um meio de escrever peas de software que possam ser parametrizadas como requerido por diferentes tipos. Em Ada isto feito pelo mecanismo genrico.

generic type Num is digits <>; package Float_IO is procedure Get(Item: out Num; ); procedurte Put(Item: in Num; ); end Float_IO; O nico parmetro genrico Num e a notao digits<> indica que que tem de ser um tipo de float point. Uma isntanciao pode ser: package My_Float_IO is new Float_IO(My_Float); 3.5. TERMINOLOGIA DA ORIENTAO A OBJECTOS O nco termo comum com o Smalltalk e C++ a herana. Tipos de registo no tagged so chamdos de constructos nas outras linguagens. Muitas linguagnes usam class para denotar o que o Ada chama um tipo especfico tagged (ou mais especificamente um ADT consistindo num tipo tagged mais as operaes primitivas). A razo para esta diferena que o Ada usa a palavra class para se referir a um grupo de tipos relacionados. Algumas linguagnes usam o termo class para ambos tipos especficos e o grupo de tipos. Operaes primitivas de tipos tagged em Ada so chamados mtodos ou funes virtuais pelas outras linguagens. Tipos abstractos correspondem a classes abstractas em muitas linguagnes. O conceito de subtipo no tem correspondncia em linguagens que no tm verificao de gamas e no tem relao com subclasse. 3.6. TAREFAS ... estudar s se for preciso... ver TFs CAP. 4 PROGRAMAS E BIBLIOTECAS 4.1. A BIBLIOTECA HIERRQUICA Um programa completo fomado por vrias unidades compiladas separadamente. Para evitar coliso de nomes (tipo Error_Messages, Debug_Info, que todos os programadores te^m tendncia a usar em diversos sotios do programa), o Ada tem um esquema de nomes hierrquico no nvel de livriaria. Assim, um pacote Parent pode ter um pacote filho com o nome Parent.Child. De modo a diminuir o perigo de coliso de nomes a biblioteca predefinida compreende apenas 3 pacotes cada um dos quais com um n de filhos: System, Interfaces e Ada. O pacote Ada, que o que nos interessa agora, simplesmente: package Ada is pragma Pure(Ada); --to branco como aneve end Ada; Pacotes filhos importantes so: Numerics contm a biblioteca maemtica Charcater contm pacotes para manipular as strings Text_IO, Sequential_IO e Direct_IO fornecem facilidade de input/output Muitas unidades de biblioteca so pacotes e mesmo os subprogramas so pacotes. Uma unidade filho pode aceder informao na rea privada do seu pai. Deve-se notar ainda que um pacote filho no precisa de uma clusula with ou use para o seu pai. 4.2. INPUT OUTPUT Todas as entradas e sadas so executadas em termos de outras caractersticas da linguagem. Input-Output apenas um servio fornecido por um ou mais pacotes do Ada. Esta filosofia arrisca aportabilidade, da o ARM que descreve certos pacotes standard que estaro disponveis em todas as implementaes. Vamos restringir-nos, para j, a texto simples.

A menos que especificado, toda a comunicao entre 2 ficheiros satndadrd e vamos assumir que o input do teclado e a sada o cran. No vamos ver todos os detalhes do Text_IO, mas algumas coisas, sim. with Ada.IO_Exceptions; package Ada.Text_IO is type Count is -- um tipo integer procedure New_Line(Spacing: in Count:=1); procedure Set_Col(To: in count); function Col return Count; procedure Get(Item: out Character); procedure Get(Item: out String); procedure Put(Item: in Character); procedure Put(Item: in String); procedure Put_Line(Item: in String); -- packages integer_IO and float_IO end Ada.Text_IO; ex: Set_Col(Col + 10); Put(A); Put(This is a string of characters); Vamos supor que o tipo My_Float foi declarado tendo 7 dgitos decimais. Put(12.34); -- s1.234000E+01 Put(12.34,3,4,2); -- ss1.2340E+1 Put(12.34, 3, 4, 0); -- s12.3400 O campo defeito o menor que acomoda todos os valores do tipo My_Integer permitindo ainda um sinal de menos/negativo. No nosso caso/ex: o campo defeito de My_Integer 8: Put(123); -- sssss123 Put(-123); -- ssss-123 Put(123, 4); -- s123 Put(123, 0); -- 123 C: Character; .. ex. de comunicao com o utilizador. Put(Do you want to stop? answer Y if so.); Get(C); if C = Y then Para pequenos programas que noprecisam ser portteis, como o Ada tem uma srie de pacotes no genricos (ex: Ada.Integer_Text_IO e Ada.Float_Text_IO), podemos simplesmente us-los: use Ada.Integer_Text_IO, Ada.Float_Text_IO; e depois podemos simplesmente chamar Put e Get. Exerccio 4.2. pg.50 4.3. BIBLIOTECA NUMRICA package Ada.Numerics is pragma Pure(Numerics); Argument_Error: exception; Pi: constant := 3.14159_26535_89793_23846_26433_83279_50288_41971_69399_37511; e: constant := 2.71828_18284_59045_23536_02874_71352_66249_77572_47093; end Ada.Numerics; Um filho deste fornece as funes elementares, tais como Sqrt e uma outra ilustrao do uso do mecanismo de genericidade. A sua especificao : generic type Float_Type is digits <>; package Ada.Numerics.Generic_Elementary_Functions is

function Sqrt(X: Float_TypeBase) return Float_TypeBase; -- and so on end; Outra vez h apenas um parmetro genrico simples dando o tipo float. Em ordem a chamar a funo Sqrt temos primeiro de instanciar o pacote genrico talo como fizmos para Float_IO, assim: package My_Elementary_Functions is new Generic_Elementary_Functions(My_Float); use My_Elementary_Functions; E podemos ento escrever uma chamada a Sqrt directamente. Dois outros pacotes importantes so aqueles para gerao de ns aleatrios. Cada contm uma funo Random. Um etorna um valor do tipo Float entre 0 e 1 e o outro retorna um valor aleatrio de um tipo discreto. A especificao : generic type Result_Subtype is (<>); package Ada.Numbers.Discrete_Random is type Generator is limited private; function Random(Gen: Generator) return Result_Subtype; --mais outras facilidades end Ada.Numerics.discrete_Random; A forma do parmetro formal genrico, indica que o tipo actual tem de ser um tipo discreto. Uma utilizao pode ser: use Ada.Numerics; type Coin is (Heads, Tails); package Random_Coin is new Discrete_Random(Coin); use Random_Coin; G: Generator; C: Coin; loop C := Random(G); end loop; 4.4. EXECUTANDO UM PROGRAMA tabuada da multiplicao at 10. with Ada.Text_IO, Ada.Integer_Text_IO; use Ada.Text_IO, Ada.Integer_Text_IO; procedure Multiplication_Tables is begin for Row in 1 .. 10 loop for Column in 1 .. 10 loop Put(Row * Column, 5); end loop; New_Line; end loop; end Multiplication_Tables; No ex: seguinte vamos reescrver o procedimento Print_Roots da seco 2.2. with Ada.Text_IO; with Ada.Float_Text_IO; with Ada.Numerics.Elementary_Functions; procedure Print_Roots is use Ada.Text_IO; use Ada.Float_Text_IO; use Ada.Numerics.Elementary_Functions; X: Float;

begin Put(Roots of various numbers); -- ando so on as before end Print_Roots; Se quisermos uma verso mais portvel: with Ada.Text_IO; with Ada.Numerics.Elementary_Functions; procedure Print_Roots is type My_Float is digits 7; package My_Float_IO is new Ada.Text_IO.Float_IO(My_Float); use My_Float_IO; package My_Elementary_Functions is new Ada.Numerics.Generic_Elementary_Functions(My_Float); use My_Elementary_Functions; X: My_Float; begin Put(Roots of various numbers); -- ando so on as before end Print_Roots; Para evitar escrever e compilar o mesmo cdigo, vamos coloc-lo num pacote nosso, pronto a usar sempre que necessrio. with Ada.Text_IO; with Ada.Numerics.Generic_Elementary_Functions; package Etc is type My_Float is digits 7; type My_Integer is range 1000_000 .. + 1000_000; package My_Float_IO is new ada.Text_IO.float_IO(My_Float); package My_Integer_IO is new Ada.Text_IO.Integer_IO(My_Integer); package My_Elementary_Functions is new Ada.Numerics.Generic_Elementary_Functions(My_Float); end Etc; Depois de compilar Etc, uma possvel utilizao : with Ada.Text_IO, Etc; use Ada.Text_IO, Etc; procedure Program is use My_Float_IO, My_Integer_IO, My_Elementary_Functions; end Program; Uma aproximao alternativa a declarar tudo no pacote etc primeiro compilar um pacote contendo apenas os tipos My_Float e My_Integer e depois compilar a s vrias instncias como pacotes individuais de biblioteca (relembrar que uma instanciao pode ser uma unidade de biblioteca). Com esta aproximao apenas precisamos de incluir (com clusulas with) os pacotes particulares que so requeridos pelo nosso programa. Um dos maiores benefcios do Ada que a consistncia assegurada entre unidades compiladas separadamente. um assunto relacionado o das dependncias: - Um body depende da correspondente especificao - um child depende da especificao do pai - uma unidade depende da especificao daquelas que so mencionadas com clususlas with A regra chave que uma unidade pode apenas ser compilada se todas de que depende esto presentes no ambiente da biblioteca. Exerccio 4.4 pg. 56

PARTE 2 ASPECTOS ALGORTMICOS O cap. 5 lida com os detalhes lexicais e pode ser saltado. O cap. 8 longo devido notao nomeada para agregados de arrays que uma caracterstica importante para escrever programas legveis. O cap. 10 acerca dos tipos de acesso que so mais flexveis que em Pascal e C/C++ para alm de prevenirem as referncias dangling que facilmente causam crashes em C. Por outro lado, aceder a tipos subprograma particularmente importante para escrever programas que interfaceiam com sistemas em outras linguagens. CAP: 5 ESTILO LEXICAL 5.1. ELEMENTOS LXICOS As letras do alfabeto podem ser acentuadas. Outros caracteres grficos tais como ! podem tambm ser usados em strings e literais. Os delimitadores compostos no devem ter espaos: => usado em agregados, casos, etc. .. para gamas/ranges ** exponenciao := atribuio /= no igual >= maior que ou igual <= menor que ou igual << e >> label brackets <> a caixa para parametrizao de tipos 5.3. IDENTIFICADORES identifier ::= identifier_letter {[underline] letter_or_digit} letter_or_digit ::= identifier_letter | digit Vemos que tm de comear por letra. identificadores que difiram apenas no facto de serem maisculas ou minsculas so considerados o mesmo. Mas, uma boa conveno usar minsculas para palavras reservadas e capitalizar todas as outras. 5.4. NMEROS Ou literais numricos. Os literais reais contm sempre um ponto decimal enquanto os literais inteiros nunca. O Ada restrito na mistura de tipos. ilegal usar um literal inteiro onde o contexto pede um literal real e vice-versa. 123_456_789 s para tornar mais fcil a leitura. Nos reais deve haver obrigatoriamente pelo menos um dgito de cada lado do ponto decimal. 9.84E1 98.4e0 984.0e-1 0.984E+2 984e-1 no permitido. 19E2 190e+1 1900E+0 mas no 19000e-1 nem 1900E-0 No caso da base ser diferente de 10 2#111# 16#A#E2 10x162=2560 2#101.11# Note que um literal numrico no pode ser negativo. Uma forma como 3 consiste de um literal precedido pelo operador unrio menos. 5.5. COMENTRIOS No h hiptese de, no Ada, inserir um comentrio no meio de uma linha. CHECKLIST 5 O facto de termos mnusculas ou maisculas irrelevante em todos os contextos excepto em strings e literais de caracteres. Carcter underline so significativos em identificadores mas no em literias numricos No so permitidos espaos em elementos lxicos, excepto em strings, literais de caracteres e comentrios. A presena ou ausncia de um pomto distingue os literias reais dos inteiros Os literias numricos no podem ser sinalizados Zeros no significativos so permitidos em todas as partes de um literal numrico. CAP.6 TIPOS ESCALARES 6.1. DECLARAES DE OBJECTOS E ATRIBUIES Os objectos so variveis ou constantes. I: Integer; P: Integer := 38;

I, J, K: Integer; P ,Q, R: Integer := 38; Neste 2 caso a todos (P,Q e R) dado o inicial valor de 38. Se um programa usar o valor indefinido de uma varivel no inicializada, o seu comportamento ser imprevisvel o programa ter um erro de fronteira/bounded error. Uma maneira comum de dar um valor a uma varivel usando uma atribuio: I := 36; P := Q + R; No possvel a uma instruo de atribuio dar o mesmo valor a vrias variveis. S na declarao, da a diferena entre declarao ( uma forma abreviada de vrias atribuies) e atribuio. Claro que uma constante deve ser inicializada na sua declarao, caso contrrio ser intil: Pi: constant Float := 3.14159_26536; Pi: constant := 3.14159_26536; uma boa prtica. Mas note-se que o tipo no pode ser omitido nas declaraes de variveis numricas. Tecnicamente isto uma declarao de um n e meramente fornece um nome para o n. 6.2. BLOCOS E MBITOS / SCOPES O mais simples fragmento de um texto que inclua declaraes e instrues um bloco. declare I: Integer := 0; begin I := I + 1; end; Os blocos pode ser indefinidamente aninhados. Um bloco uma instruo. No fim do bloco todas as coisas que foram declaradas nesse bloco deixam de existir. declare I: Integer := 0; K: Integer := I; begin permitido. A ordem importante em jargo, elaborao linear de declaraes. Scope e Visibilidade so diferentes. Scope a regio do texto onde uma entidade tem algum efeito. No caso de um bloco o scope de uma varivel (ou constante) estende-se do incio da sua declarao at ao fim do bloco. Dizemos que visvel num dado ponto se o seu nome puder ser utilizado para se referir a ela nesse ponto. Um objecto escondido por uma declarao de um novo objecto com o mesmo identificador. 6.3. TIPOS Um tipo caracterizado por um conjunto de valores e um conjunto de operaes primitivas. Todos os tipos tm um nome o qual introduzido na declarao. A ideia de uma forma lexical representar 2 ou mais coisas diferentes conhecida por overloading/sobrecarga. A tipagem forte permite detectar muitos erros cedo, em compilao. type Colour is (Red, Amber, Green); 6.4. SUBTIPOS Um subtipo caracteriza um conjunto de valores que apenas um subconjunto de valores de algum tipo. O subconjunto definido por meio de uma restrio. O subtipo toma todas as operaes. subtype Day_Number is Integer range 1..31; 1..31 a restrio de gama. D: Day_Number; I: Integer; D := I; legal embora possa dar Constraint_Error. I := D; funciona sempre. D: Integer range 1..31; podia ter sido escrito e evitar a def. de um subtipo. subtype Day_Number is Integer; legal mas no tem grande utilidade. subtype Feb_Day is Day_Number range 1.29; legal subtipo de subtipo.

Os exemplos acima mostraram restries com froneiras estticas. Mas, em geral, as fronteiras podem ser dadas por expreses arbitrrias e assim o conjunto de valores de um subtipo no necessita de ser esttico. Mas o tipo . Em captulos posteriores, encontraremos vrios contextos nos quais uma restrio explcita no permitida; um subtipo tem de ser introduzido para estes casos. Referimo-nos a um nome de um subtipo como uma marca de subtipo e forma consisitindo de uma marca de subtipo seguida de uma restrio opcional como uma indicao de subtipo como se mostra pela sintaxe: subtype_mark ::= subtype_name subtype_indication ::= subtype_mark [constraint] Ou seja, h casoonde se pode usar uma marca mas a indicao mais geral e permitida em declaraes de objectos. O objectivo dos subtipos detectar erros mais cedo e aumentar a eficincia do programa. 6.5. TIPOS NUMRICOS SIMPLES P: Integer range 1..I+J; legal. O mnimo valor do tipo Integer dado por IntegerFirst e o mximo valor por IntegerLast. Estes so os nosso primeiros exemplos de atributos. Dois subtipos teis so: subtype Natural is Integer range 0..IntegerLast; subtype Positive is Integer range 1..IntegerLast; subtype Chance is Float range 0.0 .. 1.0; / a diviso inteira e trunca na direco de zero. /= diferente. Se tivermos um n Integer e outro Float, temos de escrever Float(I) + F ou Integer(F) + I. Converses de Float para Integer arredondam e no truncam. 7/3 = 2 7 rem 3 = 1 (-7)/3 = -2 (-7) rem 3 = -1 7/(-3) = -2 7 rem (-3) = 1 (-7)/(-3) = 2 (-7) rem (-3) = -1 o resto e o quociente esto sempre relacionados por (I/J) * J + I rem J = I O sinal do resto sempre igual ao do primeiro operando, no rem. A operao mod, por outro lado, tem um comportamento de incremento uniforme. Podemos olhar para mod como dando o resto correspondente diviso com truncagem na direco do menos infinito. Assim: 7 mod 3 = 1 7 mod (-3) = -2 (-7) mod 3 = 2 (-7) mod(-3) = -1 O sinal do resultado sempre igual ao do 2 operando. No podemos A**B**C temos de usar parnteses 6.6. TIPOS ENUMERADOS type Colour is (Red, amber, Green); type Stone is (Amber, Beryl, Quartz); Normalmente tiramos qual do contexto, mas em casos em que isso no seja possvel, podemos qualificar o literal colocando-o entre parnteses e preced-lo por uma marca de subtipo e um Colour(Amber) Um tipo enumerado vazio no permitido. subtype weekday is Day range Mon..Fri; D: Weekday; ou D: Day range Mon..Fri; Os atributos First e Last aplicam-se a tipos enumerados e subtipos: ColourFirst = Red H atributos funcionais predefinidos/construdos: ColourSucc(Amber) = Green ColourPos(Red) = 0 O oposto de Pos Val ColourVal(0) = Red Red < Green is True 6.7. O TIPO BOOLEANO type Boolean is (False, True);

if Today = sun then Tomorrow := Mon; else Tomorrow := Daysucc(Today); end if; As precedncias de and, or e xor so iguais mas menores que qualquer outro operador. B and C or D ilegal O not tem precedncia maior. 6.8. CLASSIFICAO DE TIPOS Os records podem ser taggados e parametrizados com os chamados discriminantes, como veremos. Os atributos Pred e Succ (mas no Pos e Val9 tambm se aplicam a tipos reais, retornando o nmero implementado adjacente. SRange equivalente a SFirst..SLast. IntegerMin(5,10) = 5 Float(I) uma converso enquanto Integer(I) uma qualificao, que se usa normalmente para eliminar a ambiguidade. Assim Positive(I) checa se I positivo. 6.9. SUMRIO DAS EXPRESSES in e not in permitem-nos testar se um valor est dentro de uma gama especfica ou no (incluindo os valores fronteira) ou se satisfaz uma restrio implicada por um subtipo: I not in 1..10 I in Positive Today in Weekday Notar que h uma das situao em que temos de usar uma marca de subtipo em vez de uma indicao de subtipo. No podamos Today in Day range Mon..Fri mas podamos Today in Mon..Fri No and e no or no h ordem de avaliao dos operandos. No caso do and then e or then o operando esquerdo sempre avaliado primeiro. Suponhamos que temos de testar I/J > K e queremos evitar o risco de J ser zero: J/=0 and then I/J > K. Tambm no podem ser misturados sem parnteses. Constraint_Error aparece/aplica-se a todos os tipos de violaes de gamas. CHECKLIST 6 Declaraes e instrues so terminadas por ponto e vrgula Inicializao, tal como atribuio, usa := Qualquer valor inicial avaliado para cada objecto numa declarao Elaborao de declaraes linear O identificador de um objecto no pode ser usado na sua prpria declarao Cada definio de tipo introduz um tipo bem distinto Um subtipo no um novo tipo mas meramente uma abreviatura para um tipo com uma possvel restrio Um tipo sempre esttico, um subtipo no precisa de o ser No permitido modo misto na aritmtica Distinguir mod e rem para nmeros negativos Exponenciao com expoente negativo apenas se aplica a tipos reais Tomar cuidado com as precedncias dos operadores unrios Um tipo escalr no pode ser vazio, um subtipo pode Max, Min, Pos, Val, Succ e Pred em subtipos so o mesmo que nos tipos base First e Last so diferentes para subtipos Qualificao usa um Ordem de avaliao de operadores binrios no est definida Distinguir entre and e or e and hen e or then CAP. 7 ESTRUTURAS DE CONTROLO H 3 estruturas de controlo sequencial: if, case e loop 7.1. INSTRUO IF if Hungry then

Eat; end if; Notar que o end if sempre precedido de um ponto e vrgula. Isto porque os pontos e vrgula terminam instrues em vez de as separar como no Pascal. if Today = Sun then Tomorrow:=Mon; else Tomorrow := DaySucc(Today); end if; O Ada no uma linguagem de expresses, por isso no podemos Tomorrow := if Today = Sun then Mon else Daysucc(Today) end if; if A = 0.0 then -- caso linear else if B**2 4.0*A*C >= 0.0 then -- razes reais else -- razes complexas end if; isto feio, logo: if A=0.0 then -- caso linear elseif B**2 4.0*A*C >= 0.0 then -- razes reais else -- razes complexas end if; Os elseifs no so a soluo pois obscurecem a simetria e a excluso mtua dos 4 casos. 7.2. INSTRUO CASE case order is when Left => Turn_Left; when Right => Turn_Right; when Back => Turn_Back; when On => null; end case; case Today is when Mon | Tue | Wed | Thu => Work; when Fri => Work; Party; when Sat | Mon => null; end case; Se valores sucessivos tiverem a mesma aco: when Mon..Thu => Work; case Today is when Mon..Thu => Work; when Fri => Work; Party; when others => null; end case; Exemplos de gamas discretas so: Mon..Thu Day range Mon..Thu Weekday Weekday range Mon..Thu case Weekday(Today) is when Mon..Thu => Work; when Fri => Work; Party; end case; Mas se Today tomar um valor no em Weekday, aparece uma Constraint_Error. . Todos os possveis valores da expresso depois de case tm de ser cobertos uma e s uma vez. . Todos os valores e gamas depois de when devem ser estticas - Se others usado deve ser o ltimo

7.3. INSTRUO DE LOOP loop sequence_of_sattements end loop;

10.7. ACESSO A SUBPROGRAMAS A capacidade de passar subprogramas como parmetros de outros subprogramas. Assim , no Ada 95 um tipo de acesso pode referir-se a um subprograma; tal acesso a um valor de um subprograma pode ser criado pelo atributo Access e um subprograma pode ser chamado indirectamente por desreferenciao de tal valor de acesso: type Math_Function is acess function (F: Float) return Float; Do_It: Math_Function; X, Theta: Float; e o Do_It pode ento apontar para funes tais como Sin, Cos, Tan e Sqrt que assumimos que tenham especificaes tais como: function Sin(X: Float) return Float; podemos depois atribuir um acesso apropriado ao valor de um subprograma: Do_It := SinAcess; e depois: X:= Do_It(Theta); equivalente a X:= Do_It.all(Theta) mas o .all s preciso se no houver parmetros. Este mecanismo pode ser usado para programar seleco dinmica geral e para passar subprogramas como parmetros. O procedimento ex. seguinte aplica a funo passada com parmetro a todos os elementos de um array. procedure Iterate(Func: in Math_Function; V: in out Vector) is begin for I in VRange loop V(I) := Func(V(I)); end loop; end Iterate; A_Vector: Vector := (100.0, 4.0, 0.0, 25.0); .. Iterate(SqrtAcess, A_Vector); --A_Vector agora (10.0, 2.0, 0.0, 5.0) o mesmo tipo de mecanismo se pode aplicar a procedimentos. type Integrand is acess function (X: Float) return Float; function Integrate(F: Integrand; A,B : Float) return Float; e ento: Area:= Integrate(LogAcess, 1.0, 2.0); Um paradigma comum dentro da indstria de controlo de processos implementtar controlo sequencial atravs de sucessivas chamadas de um n de aces. Um compilador sequencial pode interactivamente construir um array dessas aces a que se obedecer: type Action is access procedure; Action_Sequence: array(1..N) of Action; .. construir o array e depois obedecer a ele: for I in Action_SequenceRange loop Action_Sequnce(I).all; end loop; Consideremos agora um possvel fragmento de um sistema que conduz os controlos no cockpit de uma mtica Ada Airlines. H um n de botes fsicos na consola e queremos associar aces diferentes a cada: type Button; type Response_Ptr is acess procedure (B: in out Button); type Button is record Reponse: Response_Ptr; ... outros aspectos do boto end record; procedure Associate(B: in out Button; ...); procedure Push(B: in out Button); procedure Set_Response(B: in out Button; R: in Response_Ptr); os bodies podem ser: procedure Push(B: in out Button) is begin

B.Response(B); --chamada indirecta end Push; procedure Set_Response(B: in out Button; R: in Response_Ptr) is begin B.Response:= R end Set_Response; Podemos agora especificar o conjunto de aces que queremos que sejam feitas quando se prime um boto: Big_Red_Button: Button; procedure Emergency (B: in out Button) is begin Broadcast(mayday); Eject(Pilot); end emergncy; Associate(Big_Red_Button, ); Set_Response(Big_Red_Button, EmergencyAcess); Push(Big_Red_Button); Isto tudo no pode ser aplicado a subprogramas considerados intrnsecos. CHECKLIST 10 - uma declarao incompleta pode apenas ser usada num tipo acesso - o mbito de um objecto alocado o memso do tipo de acesso - objectos de acesso tem o valor inicial null por defeito - um alocador num agregado avaliado para cada valor do index - um alocador com um valor inicial completo usa um - um tipo geral de acesso tem all ou constant na sua definio - acesso pode apenas ser aplicado a subprogramas no intrnsecos e a objectos aliasados - cuidado com Unchecked_Acess - um parmetro de acesso nunca pode ser null - converso para um tipo de acesso especfico de pool no permitido.

CAP. 13 PROGRAMAO ORIENTADA A OBJECTOS Vamos ver as caractersticas bsicas do Ada que suportam a OOP: a capacidade de estender um tipo com novos componentes e operaes; identificar um tipo especfico em run time e seleccionar uma operao particular dependendo do tipo especfico. A maior meta a reutilizao. 13.1. EXTENSO DE TIPOS Na seco 11.3 vimos que era possvel declarar um novo tipo como derivado de um existente e como isso permite a tipagem forte. As operaes herdadas podem ser sobrecarregadas eoutras operae primitivas podem ser adicionadas se a derivao estiver numa especificao de pacote. Agora iremos ver uma derivao mais flexvel onde podemos adicionar componentes extra a um record. Isto conduz-nos a uma rvore de tipos onde cada tem os componentes do pai mais outros componentes. E o ideal determinar o tipo da rvore em run time. A informao adicional que permite isso um componente escondido chamado tag. Assim, os tipos record podem ser extendidos na derivao desde que estejam marcados como tag. package Objects is type Object is tagged -- raiz da rvore record X_Coord: Float; Y_Coord: Float; end record; function Distance(O:Object) return Float; function Area(O:Object) return Float; end Objects; with Objects; use Objects; package Shapes is type Circle is new Object with record Radius: Float; end record; function Area(C:Circle) return Float; type Point is new Object with null record; type Triangle is new Object with record A, B, C: Float; end record; function Area(T: Triangle) return Float; end Shapes; Todos os tipos taggados tm tagged ou with na sua declarao. A funo Area para Object devia ser abstracta de modo a que no possa acidentalmente herdada. A converso de tipos sempre permitida na direco da raiz, mas um agergado de extenso requerido na direco oposta, em ordem a dar os valores para os componentes adicionais. O: Object := (1.0, 0.5); C: Cricle := (0.0, 0.0, 34.7); T: Triangle; P: Point; O := Object(C); ... C := (O with 41.2); T := (O with A => 3.0, B => 4.0, C => 5.0); P := (O with null record); type Cylinder is new Circle with record Height: Float;

end record; Cyl := (O with Radius => 41.2, Height => 231.6); Cyl := (C with Height => 231.6); Cyl := (Object(T) with 41.2, 231.6); Por vezes no possevl dar uma expressa de um tipo antecessor. Nessa ocasio podemos dar uma marca de subtipo. Os componetes correspondentes ao tipo antecessor so inicializados com os valores default. C:=(Object with Radius => 41.2); e as coordenadas de C no so definidas. type Object is tagged record X_Coord: Float := 0.0; Y_Coord: Float := 0.0; end record; e ento o Circle estar tambm, por defeito, na origem. Vejamos as semelhanas e diferenas entre extenso de tipos normais e extenso de tipos taggados. - componentes existentes so herdados - herana, sobrecarga e adio de operaes primitivas so permitidas nos memsos lugares; operaes adicionais so apenas permitidas se a derivao ocorre no mesmo pacote. - derivao pode ocorrer no mesmo pacote do pai e herda todas as operaes primitivas mas no mais operaes primitivas podem ser adicionadas ao pai. Diferenas: - apenas o tipo record pode ser taggado e apenas um tipo taggado pode ter componentes adicionais - converso de tipos apenas permitida na direco do antecessor para um tipo taggad, e em ambas as direces para tipos no taggados. - operaes herdadas de tipos taggados no so intrnsecas e assim o atributo de acesso pode ser-lhes aplicado. - Se uma operao herdada asobrecarregada ento a conformidade de requisitos diferente: no caso do tipo taggado deve haver conformidade de subtipos, no no taggado apenas conformidade de tipos. - um tipo derivado deve estar ao mesmo nvel de acesso do tipo pai no caso do taggado, enquanto pode estar em qualquer lado no mbito do pai nos no taggados. Isto quer dizer que no podemos fazer extenso de tipos num bloco interior ou subprograma. Exemplo do uso de tipos taggados para construir um sistema como uma hierarquia de tipos: package Reservation_System is type Position is (Aisle, Window); type Meal_Type is (Green, White, Red); type Reservation is tagged record Flight_Number: Integer; Date_Of_Travel: Date; Seat_Number: String(1..3) := ; end record; procedure Make(R: in out Reservation); procedure Select_Seat(R: in out Reservation); type Basic_Reservation is new Reservation with null record; type Nice_Reservation is new Reservation with record Seat_Sort: Position; Food: Meal_Type; end record; procedure Make(NR: in out Nice_Reservation); --sobrecarrega procedure Order_Meal(NR: in Nice_Reservation); type Posh_Reservation is new Nice_Reservation with record Destination: Address;

end record; procedure Make(PR: in out Posh_Resrvation); procedure Arrange_Limo(PR: in Posh_Reservation); end Reservation_System; package body Reservation_System is procedure Make(R: in out Reservation) is begin Select_Seat(R); end Make; procedure Make(NR: in out Nice_Reservation) is begin Make(Reservation(NR)); -- make as plain reservation Order_Meal(NR); end Make; procedure Make(PR: in out Posh_Reservation) is begin Make(Nice_reservation(PR)); -- make as nice reservation Arrange_Limo(PR); end make; procedure Select_Seat(R: in out Reservation) is separate; procedure Order_Meal(NR: in Nice_Reservation) is separate; procedure Arrange_Limo(PR: in Posh_Reservation) is separate; end Reservation_System; Cada distinto corpo para Make contm apenas o cdigo relevante para o tipo e delega outro processamento para o seu pai usando o tipo explcito de convero. Isto evita repetio de cdigo e simplifica a manuteno. Se mais tarde houver outros tipos de viagem, no preciso recompilao nem resteste. with Reservation_System; package Supersonic_Reservation_System is type Supersonic_Reservation is new Reservation_System.Reservation with record Champagne: Vinatge; -- outros components do supersnico end record; procedure Make(SR: in out Supersonic_Reservation); end Supersonic_Reservation_System; 13.2 POLIMORFISMO Precisamos agora de um meio de manipular qualquer tipo de Reservation e process-lo de acordo. Isso faz-se atravs da introduo da noo de tipos de classes largas que fornecem polimorfismo. Cada tipo taggado T tem um tipo associado TClass, que compreeende a unio de todos os tipos na rvore. Por ex. um valor de qualquer dos tipos de reservas pode ser convertido para ReservationClass. Cada valor do tipo de classe larga tem um tag que identifica o seu tipo particular em run time. O tipo TClass tratado como um tipo indefinido (por causa do espao). Como consequncia, apesar de podermos declarar um objecto de um tipo de classe larga, ele tem de ser restringido, mas a restrio no dada explicitamente mas sim inicializando-o com um valor de um tipo especfico: NR: Nice_REservation; RC: ReservationClass := NR; apesar de isto no ser muito til. De mais importncia o facto de um parmetro formal pode ser de um TCL e o parmetro actual de um tipo especfico. Imaginemos que temos uma fila de reservas para processar. Isso pode ser feito por uma rotina central que s saber o tipo particular em run time: procedure Process_Reservation(RC: in out ReservationClass) is

begin Make(RC); --despacha de acordo com o tag .. end Process_Reservation; Pode ser implementado eficientemente, por exemplo por uma tabela indexada pelo tag, que tem um apontador para o incio do cdigo correspondente. Todas as operaes no podem ser removidas na derivao; s modificadas ou adicionadas. As razes para as restries na derivao de tipos taggados mencionadas na seco anterior podem agora ser explicadas. Uma operao sobrecarregada tem de ter conformidade de subtipo de modo a que a chamada funcione sempre dinamicamente. E a extenso tem de ter o mesmo nvel de acessibilidade pois as operaes de despacho esto ao memso nvel; isto evita protenciais problemas com variveis no locais. O procedimento anterior no operao primitiva e por isso no herdada 8nem sobrecarregada). frequente vantagem usar uma classe larga em vez de uma operao primitiva se, por natureza, se aplicar a todos os tipos da classe. Ex: function Distance(O: ObjectClass) retrun Float; Podemos escrever type Reservation_Ptr is access all ReservationClass; A flexibilidade dos tipos de acesso um factor chave na programao de classe largas. Uma lista heterognea pode ser feita da forma bvia usando: type Cell; type Cell_Ptr is access Cell; type Cell is record Next: Cell_Ptr; Element: Reservation_Ptr; end record; e a rotina central pode ento manipular as reservas usando um valor de acesso co o parmetro. procedure Process_Reservation(RP: in Reservation_Ptr) is begin Make(RP.all); --despacha para o Make apropriado ... end Process_Reservation; List: Cell_Ptr; -- lista de resrevas ... while List /= null loop Process_reservation(List.Element); List := List.Next; end loop; fundamental na programao de classes largas manipular objectos via referncais; isto porque os objectos podem ser de tamanhos diferentes. type Element; type element_ptr is access all ElementClass type Element is tagged record Next: Element_Ptr; end record; type Reservation is new Element with record Flight_Number: Integrer; Date_Of_Travel: Date; Seat_Number: String(1..3) := ;

end record; igual ao anterior. As vrias reservas podem agora ser juntas para formar uma lista (fig. 13.3.) A manipulao destas listas ou filas comum em OOP, pelo que devemos ter um pacote com operaes para isso: package Queues is Queue_Error: exception; type Queue is limited private; type Element is tagged private; type Element_Ptr is access all ElementClass; procedure Joint(Q: access Queue; E: in Element_ptr); function Remove(Q: access Queue) return Element_Pyr; function Length(Q:Queue) return Integer; private type Element is tagged record Next: Element_Ptr; end record; type Queue is limited record First, Last: Element_Ptr; Count: Integer :=0; end record; end Queues; Este pacote ilustra muitos pontos. Escondemos o interior de Queue e Element, fazendo-os privados. O primeiro tambm limited pois a atribuio no deve ser permitida (baralharia os ponteiros), e tambm para garantir que a implementao do corpo no tente tambm fazer. Isto importante pois os filhos tambm vem a parte privada. O Element tagged o que permite ao utilizador extend-lo mesmo sem conhecer os detalhes. A passagem de ponteiro para a funo Remove, em vez de um parmetro in out melhora a funo mas temos de criar uma referncia para uma queue o que significa marc-la como aliasada ou cri-la com um alocador. with Queues; package Reservation_System is type Reservation is new Queues.Element with record end record; end Reservation_System; e depois criar e colocar reservas numa fila com instrues do tipo: type Queue_Ptr is access Queue; The_Queue: Queue_Ptr := new Queue; New_Resvn: Reservation_Ptr := new Nice_Reservation; Join(The_Queue, Element_Ptr(New_Resvn)); Podemos tambm remover Next_Resvn: Reservation_Ptr; ... Next_Resvn := Reservation_Ptr(Remove((The_Queue)); Process_Reservation(Next_Resvn); Resumindo as regras quanto converso de tipos e tipos taggadso: - Converso entre dois tipos especficos s permitida na direco da raiz. - Converso de um tipo especfico para uma classe tipo wide de qualquer tipo antecessor permitido. S no antecessor, no .

- O contrrio permitido desde que o tipo do valor actual seja descendente do tipo especfico. requerido checagem dinmica. - Converso entre 2 classes wide types permitida desde que o valor actual esteja na classe alvo. requerido checagem dinmica. - Converso entre tipos de acesso permitida desde que o tipo designado possa ser convertido na mesma direco. - Parmetros de tipos taggados so sempre passados por referncia e considerados aliasados. 13.3. TIPOS ABSTRACTOS declarado apenas como fundao de uma posterior derivao. No se pode declarar objectos dele. Um tipo abstracto pode ter subprogramas primitivos abstractos; no tm corpo e no podem ser chamados. So apenas contentores. prosseguindo com o nosso exemplo, o pacote bsico pode ser apenas: package Reservation_System is type Reservation is abstract tagged null record; type Reservation_Ptr is access all ReservationClass; procedure Make(R: in out Reservation) is abstract; end Reservation_System; package Reservation_System.Subsonic is type Position is (Aisle, Window); type Meal_Type is (Green, White, Red); type Basic_Resrvation is new Reservation with record Flight_Number: Integr; Date_Of_Travel: Date; Seat_Number: String(1..3) := ; end record; -- agora fornecer um subprograma concreto para o make abstracto procedure Make(BR: in out Basic_reservation); procedure Select_Seat(BR: in out Basic_Reservation); type Nice_reservation is new Basic_reservation with record Seat_Sort: Position; Food: Meal_Type; end record; procedure Make(NR: in out Nice_Reservation); procedure Order_Meal(NR: in Nice_Reservation); type Posh_Reservation is new Nice_reservation with record destination: Address; end record; procedure Make(PR: in out Posh_reservation); procedure Arrange_Limo(PR: in Posh_Reservation); end Reservation_System.Subsonic; outro ex: type Person is abstract tagged record Birth: Date; end record; e depois derivar os tipos Homem e Mulher. possvel derivar um tipo abstracto de um concreto ou de outro abstracto. 13.4. OPERAES PRIMITIVAS Um objecto carrega uma indicao da identificao do seu tipo com ele. type Person is abstract tagged record

Birth: Date; end record; type Man is new Person with record bearde: Boolena; end record; type Woman is new Person with record Children: Integr; end record; O tag pode ser implicitamente testado para saber se homem ou mulher. if P in Woman then -- processamento especial para as mulheres end if; onde P do tipo da classe larga PersonClass. Tambm possvel testar uma tag explicitamente: if PTag = Woman then o valor do atributo tag privado (mas no limitado) do tipo Tag declarado no package Ada.Tags. podemos declarar varibveis do tipo Tag da maneira habitual. Assim, Expanded_Name(ObjTag) retorna a string OBJECTS.CIRCLE por ex. tambm podemos escrever if P in WomanClass then que cobre todos os tipos derivados de Woman tambm. Melhor porque o programa pode ser extensvel. IMP: - O despacho s ocorre quando se chama uma operao primitiva e o parmetro actual de uma classe wide o parmetro de controlo. Assim, Make(RC) uma chamada ao despacho. Make(Reservation(NR)); no . Uma operao primitiva pode ter vrios parmetros de controlo mas tm de ser todos do mesmo tipo, logo no possvel declarar: procedure Something(C: Circle; T: Triangle); na especificao do package shapes. Pode ser noutro package mas no ser uma operao primitiva.