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

notas-de-aula- Schneider


DisciplinaProgramação I20.493 materiais239.718 seguidores
Pré-visualização11 páginas
ainda, operações 
padrão de atribuição e comparação de equivalência e desigualdade, à critério do programador, que 
pode suprimi-las ou redefini-las.
A fim de restringir o acesso às partes de um TAD para o cliente e ao mesmo tempo oferecer essa 
informação ao compilador, Ada usou uma palavra especial (private) para modificar declarações, 
informando que elas ficam inacessíveis ao cliente.
A linguagem Modula-2 oferece \u201cmódulos\u201d que são muito semelhantes aos \u201cpacotes\u201d de Ada, com a 
restrição de que os tipos definidos em módulos são sempre ponteiros. Dessa forma, o conhecimento 
da estrutura interna dos módulos não é necessária nem mesmo ao compilador e as declarações 
separadas das implementações não são necessárias.
prof. Bruno Schneider 25
Notas de Aula de GCC105 - BCC e BSI - UFLA
Em C++ a estrutura que proporciona encapsulamento é a classe. Classes são tipos de dados. A 
ocultação de informações funciona de maneira semelhante à da Ada. Essas duas características 
juntas proporcionam um suporte mais direto aos TADs. Outras facilidades oferecidas são os 
construtores e destrutores que podem ser usados para gerenciar a inicialização, alocação e 
desalocação de recursos (ex.: memória no heap).
O suporte de Java é muito parecido como o de C++, com algumas diferenças importantes. Todos os 
tipos definidos pelo programador em Java devem ser classes. Todas as variáveis que são TADs são 
alocadas no heap e acessadas por meio de referências. Além das classes, Java permite a definição de 
pacotes (encapsulamento geral) e oferece o \u201cescopo de pacote\u201d, em que partes protegidas das 
classes são acessíveis em outras partes do pacote.
2.6.3 Tipos abstratos de dados parametrizados
Assim, como os subprogramas, tipos de dados parametrizados são de grande utilidade. Eles 
permitem generalizar tipos de dados, descrevendo tipos como \u201clista de qualquer coisa\u201d.
Ada, C++ e Java são exemplos de linguagens que proporcionam esse tipo de construção. Assim 
como nos subprogramas, elas usam o código como modelo para a construção de vários pacotes ou 
classes conforme os casos são instanciados.
2.7 Tratamento de erros
A execução de programa está sujeita a vários tipos de erros. Alguns erros acontecem ao nível de 
hardware (ex.: overflow aritmético) e outros acontecem ao nível de software (ex.: tentar remover 
elemento que não existe numa coleção). Esse último tipo pode ser tratado pelo compilador (quando 
possível) ou pela própria execução do programa.
As linguagens de programação devem facilitar o tratamento dessas condições de erro, facilitando a 
tarefa de produzir programas que lidam graciosamente com elas.
Algumas linguagens determinam que seja gerado código para detecção de erros em várias situações 
(ex.: valor inválido para o índice de um vetor), mas é desejável que permitam ao programador 
especificar o que deve ser feito nas situações de erro.
2.7.1 Código de Erros
A forma mais primitiva para lidar com erros é usar seletores que fazem uso das formas disponíveis 
para detecção de erros. Assim, as instruções de um programa são frequentemente seguidas de 
instruções que desviam o fluxo de instruções caso uma situação anormal seja detectada.
O uso de funções que relatam algum tipo de status da execução é comum na hora de projetar 
subprogramas.
Programas também retornam esse status de tal forma que os programas que os chamaram também 
possar verificar problemas na execução para tomar as medidas necessárias. Dessa forma, linguagens 
como C++ exigem que o bloco principal de um programa retorne um número inteiro. Por 
convenção, esse número deve ser zero para indicar um execução sem erros, enquanto que qualquer 
outro número indica algum tipo de erro de execução. Cada programa cria o significado dos valores 
que indicam erros, muitas vezes, tratando o valor como um vetor de bits em que cada bit indica a 
ocorrência de um tipo de erro.
O uso de funções que retornam status tem as desvantagens de (a) criar um código em que a 
prof. Bruno Schneider 26
Notas de Aula de GCC105 - BCC e BSI - UFLA
condições anormais ficam misturadas com a condição normal e (b) dificultar o projeto de funções 
que retornam o resultado de um processamento (além do status). A segunda pode ser reduzida pela 
tipificação dinâmica, que permite a criação de uma função que retorna algum tipo que representa 
erro ou um tipo que representa o resultado do processamento.
Nas bibliotecas padrão da linguagem C, o valor de retorno de um subprograma é geralmente usado 
como código de erro.
2.7.2 Manipulação de Exceções
Algumas linguagens oferecem construções para tratar condições anormais de execução detectadas 
por hardware e software, inclusive condições incomuns (não errôneas) em geral de uma mesma 
forma. O uso dessas construções é chamado de manipulação de exceções.
Essas construções tem a desvantagem de adicionar uma boa dose de complexidade à linguagem e 
consequentemente ao seu compilador. A vantagem da manipulação de exceções é o aumento da 
legibilidade e a facilidade para descrever as formas de tratar erros, o que funciona como um 
incentivo ao tratamento de erros.
2.7.2.1 Questões de projeto
A manipulação de exceções deveria proporcionar formas de reusar código para tratamento de 
exceções (ex.: se qualquer uma dessas divisões der erro faça aquilo) ao mesmo que fornece formas 
de ligar tratadores a casos especiais de execução (ex.: essa divisão por zero é especial e deve ser 
tratada de forma diferente).
É desejável permitir que o tratamento de exceções seja ligado e desligado tanto em tempo de 
execução quanto em tempo de compilação.
Outras questões de projeto da linguagem incluem:
\u2022 como e onde especificar os tratadores (subprogramas? trechos de código?), além de como 
determinar seu escopo;
\u2022 como vincular a ocorrência de uma exceção à execução do tratador;
\u2022 como e onde retomar a execução do programa depois do tratamento;
\u2022 como o usuário pode especificar exceções;
\u2022 a existência de tratadores padrão;
\u2022 a criação automática de exceções para condições comuns de erro;
\u2022 a geração de exceções predefinidas pelo próprio programa;
\u2022 a possibilidade de desativar e reativar exceções.
Uma forma popular de vincular a ocorrência de uma exceção à execução do tratador é conhecida 
como propagação de erro. Ela consiste em checar se houve erro na execução de algum subprograma 
e então repassar essa indicação para o chamador. Essa passagem que é feita manualmente usando 
códigos de erro é feita automaticamente pela manipulação de exceções.
2.8 Sistemas de tipo
A checagem de tipos é, em geral, benéfica. As linguagens precisam de sistemas para garantir a 
prof. Bruno Schneider 27
Notas de Aula de GCC105 - BCC e BSI - UFLA
checagem, preferencialmente, em tempo de compilação. Portanto, um sistema de tipos (no contexto 
de linguagens de programação) é o conjunto de regras que permite a classificação de expressões de 
acordo com um tipo.
Declarar o tipo de cada variável antes do seu uso é uma forma simples de proporcionar isso, mas 
oferece pouca flexibilidade para o programador, limitando o reuso e a facilidade de manutenção. 
Para conciliar essas duas necessidades contraditórias, pode-se usar declarações mais gerais, em que 
não se define um tipo por completo, mas que fornecem elementos suficientes para a checagem.
O conceito de polimorfismo (tratamento de tipos diferentes de maneira uniforme) é a flexibilidade 
desejada e é difícil de conciliar com a verificação de tipos.
Nas linguagens em que os tipos precisam ser completamente determinados, temos monomorfismo. 
Naquelas em que o tipo precisa ser parcialmente determinado (somente o suficiente para checagem 
de tipos nas expressões) ou em que não há sistemas de tipos, temos polimorfismo.
O polimorfismo pode então ser obtido em níveis variados, ou seja, as linguagens proporcionam 
mais ou menos recursos para o tratamento homogêneo de tipos diferentes. Alguns