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

notas-de-aula- Schneider

Disciplina:Linguagens de Programação I252 materiais732 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
“irmãs”. 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: “os dados não

ficam visíveis”. 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 “os dados não ficam acessíveis”.

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
“classes”. 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 “pacotes”. 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