Modula-3

Origem: Wikipédia, a enciclopédia livre.
Modula-3
Paradigma Imperativo, estruturado, modular
Surgido em Década de 1980
Criado por DEC e Olivetti
Estilo de tipagem forte, estática
Principais implementações CM3[1], PM3[2], EZM3[3]
Influenciada por Modula-2+, Modula-2, Pascal, ALGOL
Influenciou Java, Python[4], Caml, C#

Modula-3 é uma linguagem de programação concebida como a sucessora de uma versão atualizada do Modula-2. Apesar de ter sido influente nos meios de pesquisa, influenciando o desenvolvimento de linguagens comerciais como Java e C#), nunca atingiu adoção na indústria de forma considerável. Foi desenvolvida por Luca Cardelli, Jim Donahue, Mick Jordan, Bill Kalsow e Greg Nelson no centro de pesquisa da Digital Equipment Corporation e na Olivetti durante o final da década de 1980. Seu desenvolvimento foi influenciado pelo trabalho no Modula-2+, em uso na DEC na mesma época e que serviu para a escrita do sistema operacional do multiprocessador DEC Firefly.

As principais funcionalidades são a simplicidade e a segurança enquanto preservando o poder das linguagens de programação de sistemas. O objetivo foi continuar a tradição da segurança de tipagem do Pascal enquanto introduzindo novas construções de programação. Foi adicionado suporte para programação genérica (similiar a templates), multitarefa, tratamento de exceções, coletor de lixo, programação orientada a objeto e encapsulamento de código. Questões mais complexas como herança múltipla e sobrecarga de operadores foram omitidas.

Desenvolvimento Histórico[editar | editar código-fonte]

O projeto do Molula-3 começou em Novembro de 1986 quando Maurice Wilkes escreveu para Niklaus Wirth com algumas ideias para uma nova versão do Modula. A definição da linguagem foi completada em Agosto de 1988, e uma versão atualizada em Janeiro de 1989. Seu design foi muito influenciado pelo trabalho na linguagem Modula-2+ usada na Systems Research Center e na Acorn Computers Research Center, linguagem em que o sistema operacional para o multiprocessador DEC Firefly, usado na VAX Workstation, foi escrito. A linguagem foi influenciada por outras linguagens como Mesa, Cedar, Object Pascal, Oberon e Euclid. Durante os anos 90, o Modula-3 ganhou um papel considerável como uma linguagem para ensino, mas nunca foi utilizada amplamente na indústria. O que pode ter contribuído para isso foi o desaparecimento da Digital Equipment Corporation (DEC), uma das principais apoiadoras do Modula-3. De qualquer maneira, apesar de sua força e simplicidade, aparentemente havia pouca demanda para uma linguagem procedimental com implementação restrita à programação orientada a objetos. Por algum tempo, um compilador comercial chamado CM3, mantido por um dos implementadores chefe que foi contratado antes da DEC ser vendida para a Compaq em 1998, um ambiente integrado de desenvolvimento chamado Reactor e uma Máquina Virtual Java (JVM) extensível (licenciada em binário e em formatos fonte junto ao Reactor) foram oferecidos pela Critical Mass, Inc., mas esta empresa cessou as operações ativas em 2000 e deu algumas fontes de seus produtos para a elego Software Solutions GmbH. O Modula-3 agora é ensinado em universidades, geralmente em cursos comparativos de linguagens de programação e, seus livros, estão escassos. Essencialmente o único apoiador corporativo é a elego Software Solutions GmbH, que, desde que recebeu as fontes da Critical Mass, fez alguns lançamentos do sistema CM3 no formato fonte e binário. O IDE Reactor foi lançado como open source após vários não ser, com um novo nome CM3-IDE. Em Março de 2002 a elego assumiu também o repositório de outra distribuição ativa do Modula-3, o PM3, até então mantido na École Polytechnique de Montréal, mas que mais tarde foi continuado no trabalho do HM3 melhorado durante os anos seguintes até ser obsoleto.

Sintaxe[editar | editar código-fonte]

Segue exemplo do programa Olá Mundo:

MODULE Main; 
IMPORT IO;
BEGIN
  IO.Put ("Hello World\n")
END Main.

Todos os programas em Modula-3 tem pelo menos um arquivo módulo, enquanto que a maioria também inclua um arquivo de interface utilizado por clientes para acessar dados do arquivo módulo. Como em outras linguagens, um programa em Modula-3 deve exportar um módulo Main, que pode tanto ser uma arquivo chamado Main.m3, ou um arquivo pode chamar o procedimento EXPORT para exportar o módulo Main. MODULE Foo EXPORTS Main

Os nomes dos arquivos dos módulos são sugeridos para serem os mesmos dos módulos reais, mas o compilador irá apenas avisá-lo se forem diferentes. Outra convenção na sintaxe inclui nomear o tipo exportado de uma interface T, desde que os tipos são geralmente qualificados por seus nomes completos, portanto um tipo T dentro de um módulo nomeado Foo será nomeado como Foo.T. Isto ajuda na legibilidade. Outra convenção similar é nomear um objeto público como Public assim como em programação orientada a objetos.

Características da Linguagem[editar | editar código-fonte]

Modularidade[editar | editar código-fonte]

Primeiramente, todas as unidades de compilação são interfaces ou módulos. Uma unidade de compilação de interface, começando com a palavra chave INTERFACE, define constantes, tipos, variáveis, exceções e procedimentos. A implementação do módulo, começando com a palavra chave MODULE, fornece o código real e quaisquer constantes, tipos ou variáveis adicionais necessários para implementar a interface. Por padrão uma implementação do módulo irá implementar uma interface de mesmo nome, mas um módulo pode explicitamente ser exportado para um módulo que não seja de mesmo nome. Por exemplo, o programa main exporta um módulo de implementação para a interface Main.

MODULE HelloWorld EXPORTS Main; 
IMPORT IO;
BEGIN
  IO.Put("Hello World\n")
END Main.

Qualquer unidade de compilação pode importar outras interfaces, e sobre o controle do programador, itens contidos na interface. Tipicamente, apenas um importa a interface, e usa a notação “ponto” para acessar os itens contidos na interface (semelhante a acessar os campos de um registro). Uma utilização comum é definir uma estrutura de dados (registro ou objeto) por interface juntamente com qualquer procedimento de apoio.

Seguro vs Inseguro[editar | editar código-fonte]

Algumas capacidades são consideradas inseguras, quando o compilador não pode mais garantir se os resultados serão consistentes (por exemplo, quando sendo interface para um programa na linguagem C). A palavra chave UNSAFE prefixada na frente de uma interface ou módulo, pode ser usada para dizer ao compilador para habilitar certas características de baixo nível da linguagem. Por exemplo, uma operação insegura é ignorar o sistema de tipos usando um LOOPHOLE para copiar os bits de um inteiro em um ponto flutuante de numero real. Uma interface que importa um módulo inseguro deve ela mesma ser insegura. Uma interface segura pode ser exportada para um módulo de implementação inseguro. Este é um uso típico quando sendo interface para bibliotecas externas, onde duas interfaces são construídas (uma insegura, a outra insegura).

Genéricos[editar | editar código-fonte]

Uma interface genérica e seu módulo correspondente, prefixa na interface ou módulo a palavra chave GENERIC, e recebe como argumentos formais outras interfaces. Assim (como templates em C++) pode-se facilmente definir e utilizar tipos de dados, mas diferentemente do C++, a granularidade está no nível do modulo. Por exemplo, pode-se definir um GenericStack, então inicializá-lo com INTEIRO, REAL, ou até mesmo referencias a Objetos. Um modulo de interface seria passado para interfaces genéricas e módulos de implementação como argumentos reais, e o compilador irá gerar módulos concretos.

Rastreabilidade[editar | editar código-fonte]

Qualquer identificador pode ser rastreado para onde ele se originou, diferentemente do “include” de outras linguagens. Uma unidade de compilação deve importar identificadores de outras unidades de compilação, utilizando uma afirmação de IMPORT. Até mesmo enumerações utiliza a notação de “ponto” como utilizado para acessar um campo de um resgistro.

INTERFACE A;

TYPE Color = {Black, Brown, Red, Orange, Yellow, Green, Blue, Violet, Gray, White};

END A;
MODULE B;

IMPORT A;
FROM A IMPORT Color;
 
VAR
 aColor: A.Color;  (* Uses the module name as a prefix *)
 theColor: Color;  (* Does not have the module name as a prefix *)
 anotherColor: A.Color;

BEGIN
 aColor := A.Color.Brown;
 theColor := Color.Red;
 anotherColor := Color.Orange;  (* Can't simply use Orange *)
END B.

Programação Dinâmica[editar | editar código-fonte]

O Modula-3 suporta a alocação de dados no tempo de execução. Existem dois tipos de memória que podem ser alocadas, TRACED (rastreada) e UNTRACED (não rastreada), a diferença é se o garbage collector pode ou não vê-la. NEW() é utilizado para se alocar ambas dessas classes de memória. Em um módulo inseguro, DISPOSE está disponível para liberar memória não rastreada.

Orientação a Objeto[editar | editar código-fonte]

As técnicas de programação orientada a objetos podem ser utilizadas no Modula-3, mas sua utilização não é exigida. Muitos outros recursos disponíveis no Modula-3 (módulos, genéricos) podem tomar o lugar da orientação a objetos. O suporte a Objetos é mantido intencionalmente em seus termos mais simples. Um tipo de objeto (Definido como classe em outras linguagens orientadas a objetos) é introduzido com a declaração OBJECT, que tem essencialmente a mesma sintaxe de uma declaração de RECORD (registro), apesar de que um tipo objeto é um tipo de referencia, enquanto que registros no Modula-3 não (semelhante a structs em C). Tipos exportados são geralmente nomeados como T por convenção, e cria um tipo “Public” separado para expor os métodos e dados. Por exemplo: INTERFACE Person;

TYPE T <: Public;
 Public = OBJECT 
 METHODS
   getAge(): INTEGER;
   init(name: TEXT; age: INTEGER): T;
 END;

END Person.

Isto define uma interface Person com dois tipos, T, e Public, que é definido como um objeto com dois métodos, getAge() and init(). T é definido como um subtipo de Public pelo uso do opetador <: Para criar um novo objeto Person.T, utilizamos o procedimento NEW com o método init():

VAR jim := NEW(Person.T).init("Jim", 25);

A construção REVEAL (revelar) do Modula-3 fornece um mecanismo conceitualmente simples e claro ainda que muito poderoso para esconder detalhes de implementação dos clientes, com diversos níveis “amigáveis”. Utilizamos o REVEAL para mostrar a implementação completa da interface Person acima:

MODULE Person;

REVEAL T = Public BRANDED 
OBJECT 
 name: TEXT;   (* These two variables *)
 age: INTEGER; (* are private. *)
OVERRIDES
 getAge := Age;
 init := Init;
END;

PROCEDURE Age(self: T): INTEGER =
 BEGIN
   RETURN self.age;
 END Age;

PROCEDURE Init(self: T; name: TEXT; age: INTEGER): T =
 BEGIN
   self.name := name;
   self.age := age;
 RETURN self;
 END Init;

BEGIN
END Person.

Veja que o uso da palavra chave BRANDED, que marca objetos para fazê-los únicos de forma a evitar equivalência estrutural. BRANDED pode pegar uma string como argumento, mas quando é omitida, uma string única é gerada para o programador. O Modula-3 é uma das poucas linguagens de programação que requer que referências externas de um módulo sejam estritamente qualificadas. Isto é, uma referência no modulo A para o objeto x exportado do modulo B deve ter a forma B.x. No Modula-3 não é possível importar “todos os nomes exportados” de um módulo. Por causa dos requerimentos da linguagem em qualificação de nomes e sobrecarga de métodos, é impossível interromper um programa em execução simplesmente adicionando novas declarações a uma interface (qualquer interface). Isto possibilita a edição de programas grandes por muitos programadores, concorrentemente, sem preocupações sobre conflitos de nomes; e também possibilita a edição de bibliotecas centrais com um conhecimento firme de que nenhum programa existente será interrompido nesse processo.

Exceções[editar | editar código-fonte]

A manipulação de exceções é baseada no sistema de bloco TRY EXCEPT, que desde então se tornou comum. Um recurso que não foi adotado por outras linguagens, com exceção do Delphi, Python, Scala e Visual Basic.NET, é que a construção EXCEPT definiu um pseudo-CASE com cada exceção possível como um CASE em uma cláusula EXCEPT. O Modula-3 também suporta uma construção LOOP EXIT END que cria um laço até que um EXIT ocorra, uma estrutura equivalente a um simples laço dentro de uma cláusula TRY EXCEPT.

Multi-Thread[editar | editar código-fonte]

A linguagem suporta o uso de multi-threading, e o sincronismo entre threads. O MUTEX é uma estrutura de dados incorporada, e a declaração LOCK bloqueia o MUTEX. O tempo de execução do Modula-3 pode fazer uso de uma thread separada para o garbage collection. Existe um modulo padrão dentro da biblioteca de tempo de execução (libm3) chamada Thread, que suporta o uso de aplicações multi-thread.

Bibliografia[editar | editar código-fonte]

Referências

  1. «Critical Mass Modula-3 (CM3)» (em inglês). Consultado em 31 de março de 2013 
  2. «Polytechnique Montréal Modula-3 (PM3)» (em inglês). Consultado em 31 de março de 2013 
  3. «Ezm3: An Easier Modula-3 Distribution» (em inglês). Consultado em 31 de março de 2013 
  4. Guido van Rossum (Maio de 1996). «Foreword for "Programming Python" (1st ed.)» (em inglês). Python Software Foundation. Consultado em 31 de março de 2013 

Ligações externas[editar | editar código-fonte]