LINEAR AND SHARED OBJECTS IN CONCURRENT PROGRAMMING - Campos, Joana Correia (2010)
As linguagens de programação centradas em objectos, como o Java, conseguem detectar antecipadamente em tempo de Compilação, e assim prevenir, muitos dos erros de tipificação e de inicialização de atributos e variáveis que os programadores inadvertidamente introduzem nos seus códigos. Contudo, estas linguagens são actualmente incapazes de capturar e assinalar erros relacionados com a utilização incorrecta de objectos. Em geral, as linguagens comerciais não dispõem de suporte formal e verificável que garanta que uma instância de uma classe é usada de acordo com a intenção do programador que escreveu essa classe. O protocolo que descreve a leitura de um ficheiro serve de motivação: primeiro o ficheiro deve ser aberto, depois as suas linhas podem ser lidas uma por uma, e, antes de o programa terminar, o ficheiro deve ser fechado. Não havendo qualquer verificação do código cliente a este nível, é inevitável que o protocolo seja quebrado, e que uma tentativa (indevida) de leitura seja efectuada antes de invocada a operação que abre o ficheiro, ou que uma outra esbarre com um ficheiro fechado. Em linguagens como o Java, este tipo de erros só é tarde detectado, quando uma excepção é lançada em tempo de execução. A linguagem de programação MOOL proposta nesta tese representa uma tentativa de formalizar a utilização e o acesso a objectos. Trata-se de uma linguagem baseada em classes, que inclui primitivas disponíveis na maioria dos formalismos de linguagens centradas em objectos. Adicionalmente, a linguagem dispõe de construções sintácticas que permitem ao programador especificar como é que um objecto de uma classe deve ser usado. Através desta especificação, o programador pode (1) definir os métodos disponíveis em função do estado do objecto, e (2) indicar como o objecto pode ser referenciado quando se encontra nesse estado – por uma única referência, tratando-se assim de um objecto linear, ou sem restrições no caso de um objecto que pode ser partilhado por viários clientes. Neste trabalho, a visão abstracta que os clientes têm do estado dos objectos é designada de tipo de utilização da classe (ou class usage type). Ao contrário dos tipos comuns, na linguagem proposta os tipos dos objectos são dinâmico, variando com o seu estado. Gay et al. [38] designam de interface dinâmica a especificação global de método disponíveis numa classe com base no estado do objecto, distinguindo-a da interface estática do Java. Objectos que mudam dinamicamente o conjunto de métodos disponíveis em função do seu estado são também conhecidos na literatura como objectos não uniformes. Nierstrasz [30] foi o primeiro a estudar o comportamento de objectos não uniformes, ou activos, em sistemas concorrentes. A linguagem MOOL oferece ainda um mecanismo de concorrência que permite a criação de threads, além da primitiva sync que permite a sincronização de métodos quando, em objectos partilhados, a comunicação deve ser efectuada em exclusão mútua. A linguagem formal que é apresentada nesta tese é baseada na linguagem proposta por Gay et al. [15], que formaliza uma abordagem designada de tipos de sessão modulares. A teoria dos tipos de sessão foi proposta para a verificação em tempo de Compilação de programas cuja comunicação se processa por canais tipificados. Os tipos de sessão são propostos como forma de impor que as implementações dos canais obedecem às sequências e tipos das mensagens especificados nos protocolos de comunicação. Em geral, os protocolos podem ser expressos por tipos de sessão, independentemente da linguagem de programação em que são integrados. Os tipos de sessão têm sido integrados em viários paradigmas de linguagens de programação: cálculo pi, linguagens funcionais, linguagens centradas em objectos, CORBA, etc. O trabalho sobre tipos de sessão modulares combina, numa linguagem centrada em objectos distribuída, os tipos de sessão e a ideia de disponibilidade dos métodos de uma classe em função do estado do objecto. A modularidade da abordagem resulta de a implementação do tipo de sessão poder ser decomposta pelos viários métodos da classe, contrastando com trabalhos anteriores, no contexto de linguagens centradas em objectos, em que o tipo de sessão é implementado no corpo de um único método. O conceito de tipos de utilização desenvolvido nesta tese foi inspirado nos tipos de sessão modulares, e adaptado a um modelo de comunicação mais simples – a troca de mensagens através de chamadas de métodos. O estilo de programação proposto pretende ser simples e intuitivo, não tendo o programador de lidar com distribuição (a concorrência é efectuada por memória partilhada), mas tirando proveito das propriedades de segurança associadas aos tipos de sessão. As contribuições desta tese materializam-se na formalização da sintaxe, da semântica operacional e do sistema de tipos, que verifica as especificações em tempo de Compilação, e na implementação de um compilador de MOOL, cuja arquitectura também se descreve. No contexto dos tipos de sessão, as contribuições desta tese podem resumir-se nos seguintes pontos: _ Ao contrário de abordagens anteriores, o modelo de comunicação baseia-se exclusivamente na chamada de métodos; _ As classes são anotadas com uma especificação de utilização que estrutura a sequência de métodos que os clientes podem invocar em função do estado do objecto, a qual é enriquecida com qualificadores lin/un que permitem controlar se um objecto é linear, e uma única referência o pode usar, ou se é partilhado, não existindo restrições quanto ao número de clientes; vi _ Ao contrário de abordagens anteriores, os canais partilhados são substituídos pela primitiva de sincronização convencional que permite que certas operações num objecto sejam acedidas sem interferência de outras threads. A tese encontra-se organizada em seis capítulos. Na introdução, o exemplo do leitor de ficheiros é apresentado como motivação dos principais aspectos da linguagem e, em particular, da especificação de tipos de utilização. Segue-se um capítulo onde se apresenta um exemplo mais extenso – o sistema de leilões – que ilustra a introdução de tipos de utilização em protocolos mais complexos. No capítulo da linguagem formal, é descrita a sintaxe, a semântica operacional e o sistema de tipos. Alguns exemplos de derivação de tipos ilustram o funcionamento das regras e as mudanças operadas no tipo dos atributos `a medida que a derivação avança. A prova formal da linguagem MOOL não é apresentada nesta tese, ficando adiada para um trabalho futuro. No entanto, sendo este sistema baseado num sistema de tipos [15] para o qual é apresentada a prova formal por indução, tudo aponta para que não seja difícil provar os resultados também para a linguagem MOOL. No capítulo da implementação, são descritas as tecnologias utilizadas e a arquitectura do compilador. Desenvolvido na linguagem Java, o compilador assenta na framework do SableCC, que gera automaticamente analisadores léxicos e classes que implementam o padrão visitante, o que permitiu reduzir o esforço de implementação ao desenvolvimento da componente semântica, através da extensão destas classes. A arquitectura do compilador distingue duas fases: a fase de análise, onde, com base na árvore abstracta do programa, é construíra a tabela de símbolos e efectuada a verificação de tipos com base num algoritmo de tipificação guiado pelos tipos de utilização, e a fase de síntese, onde o código de um programa MOOL válido é traduzido para uma linguagem intermédia. O resultado desta tradução é convertido em bytecode pela plataforma open source Mono, tendo como alvo a Common Language Runtime (CLR). No capítulo do trabalho relacionado, discute-se o estado da arte em tipos de sessão, focando o contexto das linguagens centradas em objectos, em typestates, uma abordagem com a qual as ideias desta tese apresentam pontos de contacto, e em objectos lineares. Finalmente, na conclusão antecipa-se o trabalho futuro, nomeadamente a apresentação dos resultados da linguagem MOOL e o estudo de técnicas que introduzam alguma flexibilidade na utilização de objectos lineares.