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

notas-de-aula- Schneider


DisciplinaProgramação I20.572 materiais240.107 seguidores
Pré-visualização11 páginas
vezes, é desejável passar um subprograma como argumento para outro. Isso permite um 
maior reaproveitamento de código e ajuda a manter os vários subprogramas pequenos. Por exemplo, 
um subprograma de ordenação pode receber entre seus parâmetros uma função de comparação. 
Assim a ordenação será feita conforme o critério desejado (ex.: nomes de pessoas podem ser 
ordenados pelo primeiro nome ou pelo sobrenome).
Porém é desejável que o compilador possa verificar a quantidade de parâmetros e seus tipos na 
chamada ao subprograma. Assim além da informação a respeito de qual subprograma deve ser 
usado, é desejável se ter a informação a respeito de como ele deve ser chamado, ou seja, o protocolo 
do subprograma deve ser visto como seu tipo.
Mais ainda, é desejável que essa informação esteja disponível na declaração do subprograma, para 
permitir que ele seja compilado de forma independente do subprograma que é seu parâmetro.
Uma questão importante é o ambiente de referenciamento. O ambiente de referenciamento de uma 
instrução é o conjunto de nomes válidos nela. Uma instrução tem acesso às variáveis locais e às 
externas, mas quais nomes serão considerados externos? Em outras palavras, variáveis externas ao 
subprograma que é usado como parâmetro são buscadas em que ambiente? As linguagens definem 
respostas diferentes, listadas a seguir em ordem de popularidade:
\u2022 vinculação profunda: o ambiente de referenciamento é aquele em que o subprograma foi 
declarado (a posição no texto do código define a vinculação);
\u2022 vinculação rasa: o ambiente de referenciamento é aquele em que o subprograma foi ativado 
(a ordem de execução define a vinculação) - esse tipo é considerado mais perigoso e vem 
sendo abandonado;
\u2022 vinculação ad hoc: o ambiente de referenciamento é aquele em que o subprograma foi usado 
como parâmetro.
2.5.5 Subprogramas sobrecarregados
Assim como os operadores, subprogramas podem ser sobrecarregados. Para tal é preciso que cada 
versão do subprograma tenha um protocolo único. A maioria das linguagens, entretanto, exigem que 
eles tenham um perfil de parâmetro único. Essa escolha está diretamente relacionada com a forma 
pela qual a linguagens trata expressões de modo misto. No primeiro caso, diz-se que a linguagem 
oferece \u201csobrecarga dependente de contexto\u201d e no segundo caso \u201csobrecarga independente de 
contexto\u201d.
A possibilidade de omitir parâmetros interfere com a possibilidade de sobrecarga, podendo criar 
ambiguidades. Entretanto essas ambiguidades podem ser detectadas pelo compilador.
A sobrecarga é considerada um tipo de polimorfismo (polimorfismo ad hoc). Seu uso pode levar à 
implementação de subprogramas exatamente iguais em termos de instruções, mas que diferem em 
termos de tipos.
Algumas pessoas acreditam que o Pascal é uma linguagem que suporta a sobrecarga, visto que o 
compilador Free Pascal a suporta. Entretanto a linguagem não suporta sobrecarga e portanto 
programas desenvolvidos assim podem não compilar em outros compiladores [Veen 06] [Moore 10] 
prof. Bruno Schneider 21
Notas de Aula de GCC105 - BCC e BSI - UFLA
[ISO7185].
2.5.6 Subprogramas genéricos
A capacidade de encontrar erros de tipo das linguagens com vinculação estática de tipos tem um 
alto custo: perda de flexibilidade. Por vezes, uma linguagem obriga o programador a escrever a 
mesma coisa mais de uma vez, simplesmente para satisfazer as restrições do sistema de tipos.
Para possibilitar a vinculação estática de tipos e ao mesmo tempo a flexibilidade do tratamento 
igual para tipos diferentes, algumas linguagens permitem a parametrização de tipos, ou seja, a 
definição incompleta de um tipo (especificação de um tipo genérico). Essa poderosa forma de 
polimorfismo (conhecida como polimorfismo paramétrico) viabiliza a definição dos chamados 
subprogramas genéricos.
Subprogramas genéricos, são portanto, subprogramas em que a declaração de um ou mais tipos de 
parâmetros foi parametrizada. Uma outra definição possível é a que subprogramas genéricos são 
aqueles que apresentam um ou mais parâmetros de tipo genérico. Exemplos de linguagens que 
implementam tipos genéricos: Ada, C++, Haskell e Java (a partir da versão 1.5).
Ada foi a primeira linguagem com uma implementação para subprogramas genéricos. Nela (e em 
C++) A implementação de um subprograma genérico não é transformada em código pelo 
compilador e não tem efeito sobre o programa. Ela serve como um modelo (gabarito) para o 
compilador que usa esse modelo para gerar código para todos os tipos que são usados na chamada 
do subprograma.
De maneira mais imprecisa, pode-se dizer que o compilador gera código para vários subprogramas 
com o mesmo nome, um para cada tipo usado nas chamadas, tirando do programador o trabalho de 
sobrecarregar o subprograma. Em Ada, é preciso instanciar os subprogramas de forma explícita. Em 
Java, o subprograma genérico gera byte-code, da mesma forma que código comum2.
2.5.7 Compilação Separada e Independente
A compilação de partes de programas é importante. Existem duas abordagens para permitir isso: 
\u201ccompilação separada\u201d e \u201ccompilação independente\u201d. Essas partes de programas podem ser 
chamadas de \u201cunidades de compilação\u201d.
Na compilação separada, unidades de compilação precisam de informações definidas em outras 
unidades de compilação. Essas informações são usadas para verificação de tipos, então em geral 
compreendem os protocolos de subprogramas.
Na compilação independente, a compilação de uma unidade não usa informações de outras, 
tornando inviável a verificação de tipos em tempo de compilação.
2.5.8 Questões de projeto referentes a funções
As várias linguagens de programação diferem no que diz respeito a permitir efeitos colaterais em 
funções (por causa das várias complicações decorrentes - mencionadas anteriormente) e com 
relação aos tipos válidos de retorno.
A maioria das linguagens permite os efeitos colaterais e limita os tipos de retorno aos valores 
escalares (Ada é uma das exceções nos dois aspectos).
2 Generics Tutorial - Generics in the Java Programming Language (http://java.sun.com/j2se/1.5/pdf/generics-
tutorial.pdf) - pág.3.
prof. Bruno Schneider 22
Notas de Aula de GCC105 - BCC e BSI - UFLA
As restrições aos tipos de retorno são parcialmente justificadas pelo fato de que a troca de valores é 
geralmente feita via passagem por resultado, causando ineficiência para grandes quantidades de 
informação. Uma exceção comum é o tipo registro (ou tuplas) que de certo modo podem ser usados 
para retornar mais de um valor.
Nas linguagens que permitem retornar tipos compostos, a atribuição entre esses tipos pode ser 
interessante para separação dos valores em variáveis independentes. Ex.:
(encontrado, indice) := Buscar(vetor, elemento);
if (encontrado)
then print(\u201cEncontrado na posição\u201d,indice);
else print(\u201cNão encontrado\u201d);
2.5.9 Co-rotinas
São um tipo bem diferente de subprograma. Elas se prestam à uma relação de igual para igual entre 
unidade chamadora e chamada. Ainda assim, co-rotinas são hierarquicamente ligadas à uma unidade 
de programa chamada \u201cunidade mestra\u201d.
A unidade mestra cria uma série de co-rotinas que \u201cse conhecem\u201d e as inicializa. Em seguida, o 
controle é passado para uma delas que passam o controle adiante para outra co-rotina do grupo e 
assim sucessivamente até eventualmente todas acabam e o controle retorna à unidade mestra.
As co-rotinas não tem um único ponto de entrada e mantém uma memória de suas ativações 
anteriores. Os pontos em que passam o controle adiante são determinados pelo programador e cada 
vez que uma co-rotina ganha o controle de fluxo, ela retoma a execução de onde parou. A invocação 
de uma co-rotina é chamada de retomada.
As co-rotinas apareceram na linguagem SIMULA que tinha o propósito de oferecer facilidade para 
simulação de sistemas. Um dos elementos desejados na linguagem era uma forma de proporcionar