Instituto Superior Técnico Programação Avançada – 2009/2010 Primeiro Exame/Segundo Teste – 19/6/2010 Número: Nome: Escreva o seu número em todas as folhas da prova. O tamanho das respostas deve ser limitado ao espaço fornecido para cada pergunta. Pode usar os versos das folhas para rascunho. A prova tem 6 páginas e a duração é de 2.0 horas. A cotação de cada questão encontra-se indicada entre parêntesis. Boa sorte. Se pretende fazer o Segundo Teste responda apenas às perguntas 7, 8, 9, 10, 11, 12 e 13. Se pretende fazer o Exame responda a todas as perguntas. 1. (1.0) Para permitir instrospecção, a linguagem Java teve de reificar o conceito de classe e disponibilizar formas de obter uma classe a partir de uma sua instância ou, na falta desta, a partir do nome da classe ou, na falta deste, a partir de uma String contendo esse nome. Exemplifique, com pequenos fragmentos de programas Java, estas três formas diferentes de aceder a uma classe. "I am a string".getClass() String.class Class.forName("java.lang.String") 2. (1.0) Considere uma hipotética definição de uma métrica da complexidade de uma classe como sendo a soma do número total de fields públicos descritos nessa classe com o número total de métodos públicos descritos nessa classe. Escreva, em Java, uma classe denominada Metricas contendo um método estático denominado complexidade. Este método recebe uma String com o nome de uma classe e devolve um inteiro com o valor da complexidade dessa classe. import java.lang.reflect.*; class Metricas { public static int complexidade(String c) throws ClassNot Class objClass = Class.forName(c); return objClass.getFields().length + objClass.getMet } } Número: 2 3. (1.0) A linguagem Lisp inventou o quote e, posteriormente, o backquote. Para que servem? Como funcionam? Quer o quote, quer o backquote servem para facilitar a metaprogramação. O quote indica que o seu argumento é para ser tomado literalmente, sem avaliação, permitindo que fragmentos de programas possam ser tratados como dados. O backquote funciona de modo idêntico mas permite selectivamente avaliar subexpressões do seu argumento, precedendo-as do comma. Desta forma, o backquote comporta-se como um mecanismos de templates que facilita substancialmente a meta-programação. 4. (2.0) Várias propostas têm surgido para a inclusão de despacho múltiplo em Java. Explique este conceito e especule relativamente às vantagens e desvantagens que a sua implementação poderá ter em Java. Em particular, compare-o com o já existente conceito de overloading. 5. (2.0) Em CLOS, a aplicação de uma função genérica pode implicar a computação do método efectivo. Descreva as etapas dessa computação. (a) São seleccionados os métodos aplicáveis. (b) Os métodos seleccionados são ordenadas do mais especı́fico para o menos especı́fico. (c) Os métodos ordenados são combinados, produzindo o método efectivo. 6. (3.0) Pretende-se adaptar o modelo de orientação a objectos da linguagem Java de modo a permitir a utilização de valores activos. Um valor activo é um objecto Java que, quando modificado, notifica outros objectos de que isso aconteceu. A tı́tulo de exemplo, considere um objecto Java que representa um automóvel em movimento e cuja classe tem a seguinte definição: Número: 3 class Automovel extends ... { String marca; String modelo; ... float velocidadeActual; ... } Dada uma instância de um automóvel, pretende-se que seja possı́vel associar-lhe um ou mais objectos (que denominaremos listeners) de tal modo que os objectos serão notificados através da invocação de um método pré-combinado que receberá, como argumento, o objecto que foi modificado. Por exemplo, poderá ser possı́vel associar a um automóvel especı́fico um objecto gráfico que represente um velocı́metro onde a velocidadeActual desse automóvel seja continuamente apresentada à medida que o automóvel vai mudando de velocidade. Tendo este cenário em conta, proponha um mecanismo de intercessão baseado em Javassist que facilite a criação de valores activos. Não é necessário apresentar a implementação do seu mecanismo mas inclua toda a informação que considerar relevante para que outra pessoa possa realizar essa implementação sem problemas. 4 Número: 7. (2.0) Em geral, a programação orientada a aspectos permite não só o cross-cutting dinâmico mas também o cross-cutting estático. Quais são as capacidades inerentes a cada um destes conceitos? Explique. O cross-cutting dinâmico implica a modificação do comportamento de um programa, permitindo a inserção de comportamento adicional em pontos bem definidos da execução do programa. O cross-cutting estático implica a modificação da estrutura estática do programa, permitindo modificações na hierarquia de classes, a adição de métodos, a implementação de novas interfaces, etc. 8. (1.0) Descreva, por palavras suas, qual o efeito do seguinte aspecto em AspectJ: aspect FooAspect { static final int LIMIT = 100; before(Foo foo, int newBar): set(int Foo.bar) && target(foo) && args(newBar) { if (Math.abs(newBar - foo.bar) > LIMIT) { throw new RuntimeException(); } } } 9. (2.0) A enorme maioria das linguagens de programação inclui dois conceitos relacionados com a associação de nomes a valores: definição e atribuição. 5 Número: (a) (1.0) Em termos da linguagem de programação, qual é a diferença entre estes dois conceitos? (b) (1.0) Em termos da implementação dessa linguagem num avaliador meta-circular, qual é a diferença entre estes dois conceitos? 10. (1.0) A linguagem Common Lisp providencia as formas function (#’) e funcall, enquanto que a linguagem Scheme não as possui. Porquê? Explique. 11. (1.0) Discuta as diferenças entre iteradores externos (external iterators) e iteradores internos (internal iterators). • An Internal Iterator is a higher-order function that applies a function to each element of a collection. – The iteration is controlled by the producer of values. – Used in Lisp, Haskell and other Functional Languages. 6 Número: • An External Iterator is an accessor of the current element of a collection, and, potentially, of the next one. – The iteration is controlled by the consumer of values. – Used in C++, Java and other Object-Oriented Languages. 12. (1.0) Considere o operador yield tal como é usado na linguagem Python para a criação de geradores (generators). Explique como é que poderia implementar esse operador numa linguagem que permita a captura de continuações. Teria de capturar uma continuação na invocação do gerador para poder retornar um valor ao consumidor assim que se atinge o operador yield. Nesse momento, teria de capturar outra continuação para guardar o estado de computação do gerador para, na invocação seguinte, poder retormar a execução do mesmo. Esta continuação teria de ser guardada entre invocações do gerador. 13. (2.0) Considere o operador ambı́guo amb, proposto por John McCarthy, que não-deterministicamente retorna o valor de uma das expressões dadas como argumento. (a) (1.0) Utilizando operador amb, defina uma função denominada inteiro-maior-ou-igual-a que recebe um inteiro como argumento e que, não-deterministicamente, retorna um inteiro maior ou igual ao argumento. (define (inteiro-maior-ou-igual-a a) (amb a (inteiro-maior-ou-igual-a (+ a 1)))) (b) (1.0) Considere ainda o operador fail. Juntamente com o operador amb, defina uma função elemento-lista que recebe uma lista como argumento e que não-deterministicamente retorna um elemento dessa lista. (define (elemento-lista l) (if (null? l) (fail) (amb (car l) (elemento-lista (cdr l)))))