notas-de-aula- Schneider
29 pág.

notas-de-aula- Schneider


DisciplinaProgramação I20.493 materiais239.718 seguidores
Pré-visualização11 páginas
a 
execução em tempo compartilhado entre unidades de programa, como se elas estivessem 
executando ao mesmo tempo.
São geralmente implementadas na forma de laços que passam adiante o controle de fluxo a cada 
repetição.
As co-rotinas formaram a base para a programação concorrente e são a base conceitual da 
multitarefa cooperativa.
Dificultam a criação de módulos independentes de programas, uma vez que o fluxo de instruções 
precisa ser passado voluntariamente entre as várias co-rotinas. Um erro em uma co-rotina pode 
afetar todas as outras já que a execução de qualquer co-rotina depende de retomadas a partir de suas 
\u201cirmãs\u201d. Esse mesmo problema aparece em relação aos programas na multitarefa cooperativa e foi 
um forte motivo para a evolução para a multitarefa por tempo compartilhado.
Exemplos de linguagens modernas que apresentam o recurso são Lua e Modula-2.
São tidas como mais genéricas que os subprogramas comuns.
2.6 Tipos Abstratos de Dados
A abstração é importante não só nos processos como também nos dados.
Um tipo abstrato de dados (TAD) é um encapsulamento que inclui a representação de dados (ou 
modelo de dados) de um único tipo mais os subprogramas que fornecem as operações para este tipo. 
prof. Bruno Schneider 23
Notas de Aula de GCC105 - BCC e BSI - UFLA
Uma instância de um TAD é um objeto. Vários autores consideram que precisa haver ocultação de 
dados para que o encapsulamento possa ser considerado um TAD. Seguiremos essa linha.
Um encapsulamento é um agrupamento de subprogramas e os dados que eles manipulam. Assim, 
um TAD é caso especial de encapsulamento. Suporte aos TADs como única forma de 
encapsulamento pode trazer problemas relativos a operações entre tipos diferentes (ex.: somar ponto 
com vetor).
Para facilitar o entendimento, podemos pensar no ponto flutuante como se fosse um TAD. De 
maneira não muito precisa, podemos dizer que variáveis do tipo ponto flutuante são usadas para 
representar um tipo de informação (número racional); elas podem ser manipuladas com um 
conjunto de operações (somar, multiplicar, etc.); o programador não precisa conhecer a sua 
representação interna para usá-lo; não pode alterar diretamente as partes fundamentais da sua 
representação e não pode construir novas operações para ele (a não ser pela composição das 
operações existentes).
As linguagens de programação passaram a permitir que o programador crie TADs, 
preferencialmente de forma que as definições do tipo e de suas operações ficam numa unidade de 
compilação, enquanto que outras unidades de compilação podem declarar variáveis desse tipo e 
usar as operações definidas para ele.
Esconder os detalhes de um tipo de dados é importante para manter a independência entre módulos 
de um programa. Por exemplo: suponha que um compilador de uma determinada linguagem usa 
mais bits para a mantissa de um número de ponto flutuante do que outro compilador. Nesse caso, os 
programas desenvolvidos funcionam nos dois casos, e a mudança na representação de um deles não 
necessita mudança no código que faz uso dele.
Essa ideia dá origem ao conceito de ocultação de dados (data hiding). A ocultação de dados é uma 
forma de controle de acesso que limita o uso que se pode fazer de um identificador. Esse controle 
estende o controle proporcionado pelo escopo. Em linguagens em que a ocultação de dados é mais 
simples, pode-se simplesmente limitar o acesso a um nome, ou seja, mesmo que o nome seja visível 
pelas regras de escopo, o compilador pode não permitir que o nome seja usado. Em linguagens em 
que a ocultação é mais sofisticada, pode-se limitar o uso do nome de uma variável a um right-value 
numa expressão, ou seja, cria-se uma variável que é somente para leitura em determinados 
contextos.
A ocultação de dados não tem como objetivo esconder dados (no sentido de impedir que o cliente 
saiba de usa existência), como o nome poderia sugerir3. Ela proporciona proteção (no sentido de 
impedir que o cliente possa usá-los), que é importante para manter a independência entre os 
módulos de um programa. Para entender o estado de um TAD num dado instante da execução, não 
necessário olhar fora do encapsulamento, já que tais instruções não poderiam alterá-lo. Não 
poderiam porque os dados do TAD estão protegidos pela ocultação.
Dizemos que a ocultação de dados ajuda a manter a consistência de um TAD, ou seja, como o 
estado de um TAD só pode ser alterado pelas operações definidas no encapsulamento, fica mais 
fácil garantir que as várias partes do TAD fazem sentido quando vistas como um todo. Um objeto 
assim é dito um objeto consistente. Por exemplo, imagine que TAD que representa um vetor, que 
tem como características um tamanho (inteiro) e um ponteiro para um vetor dinâmico interno de 
elementos. O tamanho é usado para que seja possível saber quantos dos elementos no vetor interno 
são realmente valores do vetor TAD e quantos são lixo. Se o vetor TAD tem 2 elementos mais o 
3 Em alguns textos sobre ocultação, usa-se o termo visível ou visibilidade na explicação, como em: \u201cos dados não 
ficam visíveis\u201d. Esses termos remetem ao sentido de secreto para a palavra ocultação e por isso costumam confundir 
leitores. É preferível, então, usar algo como \u201cos dados não ficam acessíveis\u201d.
prof. Bruno Schneider 24
Notas de Aula de GCC105 - BCC e BSI - UFLA
tamanho dele vale 3, dizemos que o vetor TAD está num estado inconsistente.
Para formalizar melhor o conceito de encapsulamento, deve-se dizer que é necessário existir um 
elemento sintático da linguagem agrupando os dados e os subprogramas. Declarar um tipo de dados 
e mais alguns subprogramas que tem a finalidade de processar esse tipo de dados, sem um elemento 
sintático que engloba isso tudo não é declarar um TAD. Da mesma forma, usar um elemento 
sintático que existe para declarar TADs sem declarar dados e subprogramas que possam ser 
entendidos como um tipo de dados, não é declarar um TAD.
2.6.1 Questões de projeto
Os TADs são mais bem suportados quando a linguagem permite deixar seus nomes e os protocolos 
de suas operações acessíveis à qualquer unidade de compilação, sem tornar a estrutura interna do 
tipo e a implementação de suas operações acessíveis também.
Algumas operações genéricas podem ser pré-determinadas pela linguagem. Ex.: verificação de 
equivalência, atribuição.
Algumas operações genéricas podem ser obrigatoriamente declaradas pelo usuário. Ex.: 
comportamento de iteradores, inicialização.
As linguagens diferem ainda a respeito de restrições para os TADs (ex.: todo TAD deve ser um tipo 
de ponteiro), se eles podem ser parametrizados (ex.: vetor de ...) e o controle de acesso (permitir 
restrições ao uso desses tipos).
Algumas linguagens oferecem formas de encapsular vários tipos e suas operações. Esse recurso é 
mais geral que a definição de um TAD e pode ser usado com esse propósito.
2.6.2 Suporte nas linguagens
Por ser a base da orientação a objetos (OO), os TADs são suportados por qualquer linguagem que 
suporte o conceito da OO.
A primeira linguagem a dar um passo nessa direção foi SIMULA 67, que permitia a declaração de 
\u201cclasses\u201d. As classes eram tipos de dados declarados de tal forma que os dados e subprogramas 
ficavam encapsulados. Não havia nenhum controle de acesso e os dados poderiam ser acessados 
diretamente pelos clientes da classe. Isso gera problemas de confiabilidade e também faz com que 
esse encapsulamento nem sempre seja considerado um suporte aos TADs.
A linguagem Ada oferece encapsulamento na construção de unidades chamadas \u201cpacotes\u201d. Pacotes 
não são tipos, mas sim coleções de tipos. Ada permite a separação entre declarações e 
implementações. Oferece também suporte à ocultação de informações, proporcionando uma forma 
de evitar que os clientes tenham acesso às partes internas dos TADs. Ada oferece