Verificação de Tipos e Escopos Paradigmas de Programação Prof. Gláucya Carreiro Boechat glaucyacboechat@gmail.com
Verificação de Tipos Verificação de tipos é a atividade de assegurar que os operandos de um operador sejam de tipos compatíveis Um tipo compatível é aquele válido para o operador ou com permissão, nas regras da linguagem, para ser convertido pelo compilador para um tipo válido Essa conversão automática é chamada de coerção Um erro de tipo é a aplicação de um operador a um operando de tipo impróprio
Verificação de Tipos Se todas as vinculações forem estáticas, a verificação de tipos quase sempre poderá ser feita estaticamente Se as vinculações de tipos são dinâmicas então a verificação de tipos deve ser dinâmica
Tipificação Forte Uma linguagem de programação é fortemente tipificada se erros de tipos são sempre detectados Vantagens Permite a detecção de todos os usos equivocados de variáveis que resultem em erros de tipo Exemplos de linguagens C e C++ não são: permitem funções cujos parâmetros não são verificados quanto ao tipo Ada é quase fortemente tipificada (Java é similar)
Tipificação Forte Regras de Coerção Podem enfraquecer a tipificação forte (C++ versus Ada) Ada possui poucas regras de coerção Embora Java possua metade das regras de coerção do C++, logo sua detecção de erros é melhor do que a do C++, sua tipificação forte é bastante inferior a da Ada
Compatibilidade de Tipos Existem dos métodos diferentes de compatibilidade de tipos Compatibilidade de Nome Compatibilidade de Estrutura
Compatibilidade de Tipo de Nome Significa que duas variáveis possuem tipos compatíveis se elas estiverem na mesma declaração ou em declaração que usam o mesmo nome de tipo A compatibilidade de tipo de nome é fácil de implementar mais muito restritiva Uma variável subfaixa dos números dos inteiros não seria compatível com uma variável do tipo inteiro Type indextype = 1 .. 100; {um tipo subfaixa} Var cont : integer; index : indextype; As variáveis cont e index não são compatíveis, cont não seria atribuída a index e vice-versa
Compatibilidade de Tipo de Estrutura Significa que duas variáveis têm tipos compatíveis se os seus tipos tiverem estruturas idênticas Mais flexível, porém mais difícil de implementar
Compatibilidade de Tipos Considere os problemas de tipo entre duas estruturas: Dois registros são compatíveis no tipo se eles possuem a mesma estrutura mas usam diferentes nomes para os campos? Dois vetores são compatíveis se eles são os mesmos exceto pela faixa de indexação? Exemplo: [1..10] e [0..9] Usando compatibilidade de tipo de estrutura não é possível diferenciar entre tipos que tenham a mesma estrutura Exemplo: Diferentes unidade de velocidade, ambas ponto flutuante Celsius e Fahrenheit, ambos ponto flutuante
Escopo O escopo de uma variável é a faixa de instruções na qual a variável é visível Uma variável é visível em uma instrução se puder ser referenciada nessa instrução As variáveis não-locais de uma unidade ou de um bloco de programa são as visíveis dentro deste, mas não são declaradas lá
Escopo Estático Método para vincular nomes a variáveis não-locais Para conectar uma referência a uma variável, o compilador precisa encontrar a declaração Processo de busca: Caso a declaração não for encontrada localmente, passa-se a buscar em escopos mais amplos O pai-estático (static parent) é o subprograma no qual encontra-se a declaração Os ancestrais estáticos são todos os subprogramas até se chegar a declaração
A variável x em sub1 é declarada Escopo Estático procedure big; var x : integer; procedure sub1; begin { sub1 } ... x ... end; { sub1 } procedure sub2; begin { sub2 } ... end; begin { big } end; { big } A variável x em sub1 é declarada no procedimento big
Escopo Estático Variáveis podem ser escondidas de uma unidade quando a mesma possui uma variável com o mesmo nome C++ e Ada permitem acesso a essas variáveis escondidas Em Ada: unit.name Em C++: class_name::name program main; var x : integer; procedure sub1; begin { sub1} ...x... end; { sub1 } begin { main } ... end; { main }
Escopo Dinâmico Baseia-se na seqüência de chamada de subprogramas, não em suas relações espaciais (temporal versus espacial) Desta forma o escopo pode ser determinado apenas em tempo de execução Quando a procura por declarações locais falha, as declarações do pai-dinâmico (procedimento de chamada) são pesquisadas, e assim sucessivamente Caso nenhuma declaração for encontrada em qualquer ancestral dinâmico, haverá um erro em tempo de execução
Escopo Dinâmico - Exemplo procedure big; var x: integer; procedure sub1; begin { sub1 } ... x ... procedure sub2; var x : integer; begin { sub2 } ... end; begin { big } end; { big } BIG chama SUB2 SUB2 chama SUB1 SUB1 usa x Nesse caso, SUB1 usa o x declarado em SUB2