A apresentação está carregando. Por favor, espere

A apresentação está carregando. Por favor, espere

7 Abstração Genérica Unidades genéricas e instanciação.

Apresentações semelhantes


Apresentação em tema: "7 Abstração Genérica Unidades genéricas e instanciação."— Transcrição da apresentação:

1 7 Abstração Genérica Unidades genéricas e instanciação.
Tipos e classes parâmetros. Notas de implementação.

2 Unidades genéricas e instanciação (1)
Uma unidade genérica é uma unidade de programa que é parametrizada em relação às entidades das quais ela depende A instanciação de uma unidade genérica cria uma unidade de programa ordinária, na qual, cada parâmetro formal da unidade é trocado por um argumento Gera sob demanda uma família de unidades de programas similares, evitando a redundância de código Favorece a reusabilidade porque uma mesma unidade de programa pode ser instanciada em diferentes programas

3 Unidades genéricas e instanciação (2)
Unidades genéricas seguem o princípio da abstração Uma unidade genérica é uma abstração sobre uma declaração Possui um corpo – a declaração – e uma instanciação genérica é uma declaração que produzirá ligações pela elaboração do corpo da unidade genérica Unidades genéricas são suportadas por Ada, C++ e Java em diferentes perspectivas

4 Exemplo: pacotes genéricos em Ada (1)
Ada suporta pacotes genéricos e procedimentos genéricos generic capacity: Positive; package Queues is type Queue is limited private; procedure clear (q: out Queue); procedure add (q: in out Queue; e: in Character); procedure remove (q: in out Queue; e: out Character); private type Queue is record length: Integer range 0 .. capacity; front, rear: Integer range 0 .. capacity-1; elems: array (0 .. capacity-1) of Character; end record; end Queues; Parâmetro formal baseado em valor

5 Exemplo: pacotes genéricos em Ada (2)
package body Queues is procedure clear (q: out Queue) is begin q.front := 0; q.rear := 0; q.length := 0; end; procedure add (q: in out Queue; e: in Character) is begin q.elems(q.rear) := e; q.rear := (q.rear + 1) mod capacity; q.length := q.length + 1; end; procedure remove (q: in out Queue; e: out Character) is begin e := q.elems(q.front); q.front := (q.front + 1) mod capacity; q.length := q.length - 1; end; end Queues;

6 Exemplo: pacotes genéricos em Ada (3)
Pacotes genéricos em Ada são instanciados por uma forma especial de declaração denominada instantiation package Line_Buffers is new Queues(120); package Input_Buffers is new Queues(80); A instanciação resulta num pacote ordinário inbuf: Input_Buffers.Queue; Input_Buffers.add(inbuf, '*'); Argumentos da instanciação Argumentos da instanciação

7 Exemplo: pacotes genéricos em C++ (1)
C++ suporta funções genéricas (function templates) e classes genéricas (class templates) template <int capacity> class Queue { private: char elems[capacity]; int front, rear, length; public: Queue (); void add (char e); char remove (); } Parâmetro formal da classe genérica – denota um valor inteiro a ser conhecido durante a instanciação

8 Exemplo: pacotes genéricos em C++ (2)
Definição de construtores e métodos em separado template <int capacity> Queue<capacity>::Queue () { front = rear = length = 0; } template <int capacity> void Queue<capacity>::add (char e) { elems[rear] = e; rear = (rear + 1) % capacity; length++; } template <int capacity> char Queue<capacity>::remove () { char e = elems[front]; front = (front + 1) % capacity; length--; return e; }

9 Exemplo: pacotes genéricos em C++ (3)
Instanciação de pacotes genéricos typedef Queue<80> Input_Buffer; typedef Queue<120> Line_Buffer; A instanciação resulta em classes nas quais os parâmetros formais são substituídos pelo valor do argumento Input_Buffer inbuf; Line_Buffer outbuf; Line_Buffer errbuf; ou Queue<80> inbuf; Queue<120> outbuf; Queue<120> errbuf;

10 Exemplo: pacotes genéricos em C++ (4)
A instanciação on the fly de classes genéricas resulta num problema conceitual e em outro de ordem pragmática O problema conceitual diz respeito a equivalência de tipos Duas variáveis outbuf e errbuf declaradas com tipos Queue<120> e Queue<120> são equivalentes Mas se duas variáveis são declaradas com tipos Queue<m> e Queue<n-1>, o compilador não tem como decidir se os tipos são equivalentes  instanciações em C++ devem obrigatoriamente poder avaliar seus argumentos em tempo de compilação O problema pragmático pode levar o programador a perder o controle sobre a expansão de código Se Queue<120> ocorre em vários locais do código, um compilador não profissional pode gerar várias instâncias de Queue, enquanto um profissional geraria apenas uma única instância Estes problemas não ocorrem em Ada!

11 Tipos e classes parâmetros
Como uma unidade de programa usa um valor definido em qualquer lugar, a unidade de programa pode tornar-se genérica e parametrizada com relação a esse valor Graças ao princípio da correspondência Como uma unidade de programa usa um tipo (ou classe) definido em qualquer lugar, a unidade de programa pode tornar-se genérica e parametrizada com relação a esse tipo Tem-se uma nova modalidade de parâmetro: o parâmetro que é um tipo (ou uma classe) Unidade genéricas em Ada, C++ e Java podem ter tipos como parâmetros

12 Exemplo: tipo parâmetro em Ada (1)
Uma unidade genérica em Ada pode ser parametrizada com respeito a qualquer tipo do qual ela dependa generic type Element is private; package Lists is type List is limited private; procedure clear (l: out List); procedure add (l: in out List; e: in Element); private capacity: constant Integer := ...; type List is record length: Integer range 0 .. capacity; elems: array (1 .. capacity) of Element; end record; end Lists; Parâmetro formal do pacote genérico – denota um tipo a ser conhecido durante a instanciação

13 Exemplo: tipo parâmetro em Ada (2)
O parâmetro formal Element é usado tanto da especificação do pacote, quanto no seu corpo package body Lists is procedure clear (l: out List) is begin l.length := 0; end; procedure add (l: in out List; e: in Element) is begin l.length := l.length + 1; l.elems(l.length) := e; end; end Lists;

14 Exemplo: tipo parâmetro em Ada (3)
Instanciação do pacote genérico Lists package Phrases is new Lists(Character); O parâmetro formal Element é ligado ao tipo Character (argumento na instanciação) Depois, a especificação e o corpo de Lists são elaborados, gerando um pacote que encapsula uma lista com elementos do tipo Character sentence: Phrases.List; Phrases.add(sentence, '.'); Outra opção type Transaction is record ... end record; package Transaction_Lists is new Lists(Transaction);

15 Exemplo: tipo e função parâmetro em Ada (1)
Se uma unidade genérica não sabe nada sobre o tipo parâmetro – exceto o nome – ela ainda assim pode declarar variáveis desse tipo, mas não pode aplicar nenhuma operação sobre tais variáveis!  Unidades genéricas devem saber pelo menos algumas das operações aplicáveis ao tipo parâmetro Tipicamente, as operações de atribuição e de teste de igualdade

16 Exemplo: tipo e função parâmetro em Ada (2)
generic type Element is private; with function precedes (x, y: Element) return Boolean; package Sequences is type Sequence is limited private; procedure clear (s: out Sequence); procedure append (s: in out Sequence; e: in Element); procedure sort (s: in out Sequence); private capacity: constant Integer := ...; type Sequence is record length: Integer range 0 .. capacity; elems: array (1 .. capacity) of Element; end record; end Sequences; Parâmetro formal que denota a uma função desconhecida que recebe dois argumentos do tipo Element e retorna um resultado do tipo Boolean

17 Exemplo: tipo e função parâmetro em Ada (3)
O corpo do pacote usa o tipo Element e a função precedes, parâmetros da unidade genérica package body Sequences is procedure sort (s: in out Sequence) is e: Element; begin if precedes(e, s.elems(i)) then end; end Sequences;

18 Exemplo: tipo e função parâmetro em Ada (4)
Possível instanciação de Sequences type Transaction is record ... end record; function earlier (t1, t2: Transaction) return Boolean; -- Return true if and only if t1 has an earlier timestamp than t2. package Transaction_Sequences is new Sequences(Transaction, earlier); que pode ser usada como um pacote comum audit_trail: Transaction_Sequences.Sequence; ... Transaction_Sequences.sort(audit_trail); Outros exemplos package Ascending_Sequences is new Sequences(Float, "<"); readings: Ascending_Sequences.Sequence; ... Ascending_Sequences.sort(readings);

19 Exemplo: tipo e função parâmetro em Ada (5)
Em geral, se uma unidade genérica em Ada tem um tipo parâmetro T, ele é especificado pela cláusula type T is especificação das operações que equipam T; O compilador verifica a unidade genérica para assegurar que operações usadas por T na unidade genérica  nas operações com as quais T está equipada O compilador verifica separadamente cada instanciação da unidade genérica para assegurar que operações com as quais T está equipada  nas operações que equipam o tipo que é passado como argumento Uma vez implementada, as unidades genéricas em Ada podem ser reusada com segurança em relação a verificação de tipos

20 Exemplo: tipo parâmetro em C++ (1)
Unidades genéricas em C++ podem ser parametrizadas em relação a quaisquer tipos ou classes das quais elas dependam template <class Element> class Sequence is private: const int capacity = ...; int length; Element elems[capacity]; public: Sequence (); void append (Element e); void sort (); } Parâmetro formal que denota a um tipo qualquer desconhecido, e não apenas tipos que são classes

21 Exemplo: tipo parâmetro em C++ (2)
Implementação segue como usual template <class Element> void Sequence<Element>::sort () { Element e; if (e < elems[i]) } A utilização do operador "<" é perfeitamente legal, pois assume-se que o tipo denotado por Element "estará" equipado com tal operador O compilador rejeitará instanciações para tipos argumentos que não sejam equipados com o operador "<"

22 Exemplo: tipo parâmetro em C++ (3)
Exemplos de instanciações typedef Sequence<float> Number_Sequence; Number_Sequence readings; readings.sort(); typedef char* String; typedef Sequence<String> String_Sequence; struct Transaction { ... }; typedef Sequence<Transaction> Transaction_Sequence; O operador "<" será utilizado, mas o resultado não será o desejado! Por que? Esta instanciação será recusada pelo compilador, pois o operador "<" não equipa o tipo Transaction

23 Exemplo: tipo parâmetro em C++ (4)
Em geral, se uma unidade genérica em C++ tem um tipo parâmetro T, ele é especificado pela cláusula <class T> que não revela nada sobre as operações que equipam T. O compilador verifica cada instanciação da unidade genérica para assegurar que operações usadas por T na unidade genérica  nas operações que equipam o tipo que é passado como argumento As unidades genéricas de C++ não são uma fundação segura para reuso de software O compilador não é capaz de verificar completamente os tipos numa definição de unidade genérica, mas apenas instanciações individuais

24 Exemplo: classe genérica em Java com classe parâmetro (1)
Unidades genéricas foram introduzidas em Java com o lançamento da plataforma Java 2SE 5.0 em 2004 Classes genéricas – classes que podem ser parametrizadas em relação a outras classes class List <Element> { private int length; private Element[] elems; public List () { } public void append (Element e) { } } Parâmertro formal da classe genérica List e denota uma classe desconhecida a priori

25 Exemplo: classe genérica em Java com classe parâmetro (2)
Instanciação de classes genéricas List<Character> sentence; List<Transaction> transactions; O argumento na instanciação deve ser uma classe – tipos primitivos são proibidos List<char> sentence; Instanciação ilegal!

26 Exemplo: classe genérica em Java com classe parâmetro limitada pela interface (1)
Caso uma classe genérica assuma que a classe parâmetro está equipada com operações, a classe parâmetro deve ser especificada como implementando uma interface adequada Diz-se que tal classe parâmetro é limitada (bounded) pela interface class Sequence <Element implements Comparable<Element>> { private int length; private Element[] elems; public Sequence () { ... } public void append (Element e) { ... } public void sort () { Element e; if (e.compareTo(elems[i] < 0) } } Element é um parâmetro formal que denota uma classe desconhecida, mas que deve implementar a interface Comparable, onde o método compareTo está especificado

27 Exemplo: classe genérica em Java com classe parâmetro limitada pela interface (2)
Possível instanciação da classe genérica Sequence Sequence<Transaction> auditTrail; auditTrail.sort(); assumindo que a classe Transaction é declarada assim Class Transaction implements Comparable<Transaction> { private ...; public int compareTo(Transaction that) { } }

28 Exemplo: classe genérica em Java com classe parâmetro limitada pela interface (3)
Em geral, se uma unidade genérica em Java tem uma classe parâmetro C, ela é especificada pela cláusula C implements Interface; O compilador verifica a unidade genérica para assegurar que operações usadas por C na unidade genérica  nas operações declaradas em Interface O compilador verifica separadamente cada instanciação da unidade genérica para assegurar que operações declaradas na Interface  nas operações que equipam a classe passada como argumento Uma vez implementada, as unidades genéricas em Java podem ser reusadas com segurança em relação a verificação de tipos Desvantagens da classes genéricas em Java Somente classes podem ser parâmetros de classes genéricas Tipos primitivos são proibidos – conseqüência da incompletude de tipos em Java Não podem ser parametrizadas por valores dos quais dependam

29 Notas de Implementação
Unidades genéricas com tipos parâmetros suscitam interessantes problemas de implementação Como o tipo parâmetro denota um tipo desconhecido, o compilador não pode determinar, apenas da unidade genérica, como os valores do tipo serão representados Não há como saber o espaço de memória requerido, por exemplo Somente quando a unidade genérica é instanciada é que o compilador pode saber essa informação

30 Exemplo: implementação de unidades genéricas em Ada (1)

31 Exemplo: implementação de unidades genéricas em Ada (2)
As três instanciações anteriores definem três tipos distintos A.List B.List C.List Em geral, cada instanciação de um pacote genérico de Ada é compilado, com a geração de código objeto especializado para cada instanciação Em casos específicos, diferentes instanciações podem compartilhar o mesmo código objeto – quando os tipos envolvido têm representações similares

32 Exemplo: implementação de unidades genéricas em C++
Similar a implementação em Ada, mas com uma complicação extra As classes genéricas de C++ podem ser instanciadas on the fly Um código de programa pode conter várias declarações de variáveis do tipo List<float> No sistema de tipos de C++, todas estas variáveis têm o mesmo tipo, logo estão equipadas com as mesmas operações O desafio para o compilador é fazer com que todas estas variáveis compartilhem o mesmo código objeto

33 Exemplo: implementação de unidades genéricas em Java (1)
A implementação de classes genéricas em Java é simplificada porque elas só podem ser parametrizadas em relação a classes, que sempre são acessadas através de apontadores


Carregar ppt "7 Abstração Genérica Unidades genéricas e instanciação."

Apresentações semelhantes


Anúncios Google