Modula-3 - Modula-3

Modula-3
Modula-3.svg
Paradigmas imperativo , estruturado , procedimental , modular , simultâneo
Família Wirth Modula
Projetado por Luca Cardelli , James Donahue, Lucille Glassman, Mick Jordan; Bill Kalsow, Greg Nelson
Desenvolvedores DEC
Olivetti
elego Software Solutions GmbH
Apareceu pela primeira vez 1988 ; 33 anos atrás ( 1988 )
Versão estável
5.8.6 / 14 de julho de 2010 ; 11 anos atrás ( 14/07/2010 )
Versão de visualização
5.8.6 / 14 de julho de 2010 ; 11 anos atrás ( 14/07/2010 )
Disciplina de digitação forte , estático , seguro ou se inseguro explicitamente seguro isolado
Alcance Lexical
Plataforma IA-32 , x86-64 , PowerPC , SPARC
SO Plataforma cruzada : FreeBSD , Linux , Darwin , SunOS
Local na rede Internet www .modula3 .org
Implementações principais
SRC Modula-3, CM3, PM3, EZM3, M3 / PC Klagenfurt
Influenciado por
ALGOL , Euclid , Mesa , Modula-2 , Modula-2 + , Oberon , Pascal
Influenciado
C # , Java , Nim , OCaml , Python

Modula-3 é uma linguagem de programação concebida como sucessora de uma versão atualizada do Modula-2 conhecida como Modula-2 + . Embora tenha sido influente nos círculos de pesquisa (influenciando os projetos de linguagens como Java , C # e Python ), não foi amplamente adotado na indústria. Foi projetado por Luca Cardelli , James Donahue, Lucille Glassman, Mick Jordan (antes no Laboratório de Tecnologia de Software da Olivetti ), Bill Kalsow e Greg Nelson no Centro de Pesquisa de Sistemas (SRC) da Digital Equipment Corporation (DEC ) e no Centro de Pesquisa Olivetti ( ORC) no final dos anos 1980.

As principais características do Modula-3 são simplicidade e segurança, preservando o poder de uma linguagem de programação de sistemas. Modula-3 teve como objetivo continuar a tradição Pascal de segurança de tipo, ao introduzir novas construções para a programação prática do mundo real. Em particular, o Modula-3 adicionou suporte para programação genérica (semelhante a modelos ), multithreading , tratamento de exceções , coleta de lixo , programação orientada a objetos , revelação parcial e marcação explícita de código inseguro. O objetivo de design do Modula-3 era uma linguagem que implementasse os recursos mais importantes das linguagens de programação imperativas modernas em formas bastante básicas. Assim, recursos supostamente perigosos e complicadores, como herança múltipla e sobrecarga de operador, foram omitidos.

Desenvolvimento histórico

O projeto Modula-3 começou em novembro de 1986, quando Maurice Wilkes escreveu a Niklaus Wirth com algumas idéias para uma nova versão do Modula. Wilkes estava trabalhando na DEC pouco antes deste ponto e voltou para a Inglaterra e ingressou no Conselho de Estratégia de Pesquisa da Olivetti. Wirth já havia se mudado para Oberon , mas não teve problemas com o desenvolvimento contínuo da equipe de Wilkes com o nome Modula. A definição da linguagem foi concluída em agosto de 1988 e uma versão atualizada em janeiro de 1989. Compiladores de DEC e Olivetti logo seguiram, e implementações de terceiros depois disso.

Seu design foi fortemente influenciado pelo trabalho na linguagem Modula-2 + em uso no SRC e no Acorn Computers Research Center (ARC, mais tarde ORC quando a Olivetti adquiriu a Acorn) na época, que era a linguagem em que o sistema operacional para o A estação de trabalho VAX com multiprocessador DEC Firefly foi escrita e na qual o Acorn Compiler for Acorn C e Modula Execution Library (CAMEL) no ARC para o projeto de sistema operacional ARX da gama de computadores Acorn Archimedes baseada em ARM foi escrita. Como afirma o Relatório Modula-3 revisado, a linguagem foi influenciada por outras línguas, como Mesa , Cedar , Object Pascal , Oberon e Euclid .

Durante a década de 1990, o Modula-3 ganhou uma aceitação considerável como língua de ensino, mas nunca foi amplamente adotado para uso industrial. Contribuir para isso pode ter sido o fim do DEC, um dos principais apoiadores do Modula-3 (especialmente quando ele deixou de mantê-lo efetivamente antes que o DEC fosse vendido para a Compaq em 1998). Em qualquer caso, apesar da simplicidade e poder do Modula-3, parece que havia pouca demanda por uma linguagem compilada procedural com implementação restrita de programação orientada a objetos . Por um tempo, um compilador comercial chamado CM3 mantido por um dos principais implementadores antes da DEC SRC, que foi contratado antes da DEC ser vendida para a Compaq , um ambiente de desenvolvimento integrado (IDE) chamado Reactor e uma máquina virtual Java extensível (licenciada em código binário e formatos de código-fonte e compiláveis ​​com o Reactor) foram oferecidos pela Critical Mass, Inc., mas essa empresa interrompeu suas operações ativas em 2000 e deu parte do código-fonte de seus produtos à elego Software Solutions GmbH. Modula-3 agora é ensinado em universidades principalmente em cursos de linguagem de programação comparativa, e seus livros estão esgotados. Essencialmente, o único apoiador corporativo do Modula-3 é o elego, que herdou as fontes do Critical Mass e desde então fez vários lançamentos do sistema CM3 em código fonte e binário. O Reactor IDE foi lançado em código aberto depois de vários anos sem, com o novo nome CM3-IDE. Em março de 2002, elego também assumiu o repositório de outra distribuição Modula-3 ativa, PM3, até então mantida na École Polytechnique de Montréal, mas que mais tarde continuou com o trabalho no HM3, melhorou ao longo dos anos até que se tornou obsoleto.

Sintaxe

Um exemplo comum de sintaxe de uma linguagem é "Hello, World!" programa .

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

Todos os programas em Modula-3 têm pelo menos um arquivo de módulo, enquanto a maioria também inclui um arquivo de interface que é usado por clientes para acessar dados do módulo. Como em algumas outras linguagens, um programa Modula-3 deve exportar um módulo Principal, que pode ser um arquivo denominado Main.m3 ou um arquivo pode ser chamado EXPORTpara exportar o módulo Principal.

MODULE Foo EXPORTS Main

Recomenda-se que os nomes dos arquivos de módulo sejam iguais ao nome no código-fonte. Se forem diferentes, o compilador apenas emitirá um aviso.

Outras convenções na sintaxe incluem nomear o tipo exportado de uma interface T, uma vez que os tipos são geralmente qualificados por seus nomes completos, portanto, um tipo Tdentro de um módulo denominado Foo será nomeado Foo.T. Isso ajuda na legibilidade. Outra convenção semelhante é nomear um objeto público Publiccomo nos exemplos OOP acima.

Características da linguagem

Modularidade

Em primeiro lugar, todas as unidades compiladas são INTERFACEou implementações MODULE, de um tipo ou outro. Uma unidade de interface compilada, começando com a palavra-chave INTERFACE, define constantes, tipos, variáveis, exceções e procedimentos. O módulo de implementação, começando com a palavra-chave MODULE, fornece o código e quaisquer constantes, tipos ou variáveis ​​adicionais necessários para implementar a interface. Por padrão, um módulo de implementação implementará a interface com o mesmo nome, mas um módulo pode explicitamente EXPORTpara um módulo que não tem o mesmo nome. Por exemplo, o programa principal exporta um módulo de implementação para a interface Principal.

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

Qualquer unidade compilada pode ter IMPORToutras interfaces, embora as importações circulares sejam proibidas. Isso pode ser resolvido fazendo a importação do MÓDULO de implementação. As entidades dentro do módulo importado podem ser importadas, em vez de apenas o nome do módulo, usando a FROM Module IMPORT Item [, Item]*sintaxe:

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

Normalmente, apenas se importa a interface e usa a notação de 'ponto' para acessar os itens dentro da interface (semelhante a acessar os campos dentro de um registro). Um uso típico é definir uma estrutura de dados (registro ou objeto) por interface junto com quaisquer procedimentos de suporte. Aqui, o tipo principal receberá o nome 'T' e será usado como em MyModule.T.

No caso de uma colisão de nome entre um módulo importado e outra entidade dentro do módulo, a palavra reservada ASpode ser usada como emIMPORT CollidingModule AS X;

Seguro vs inseguro

Alguma habilidade é considerada insegura, onde o compilador não pode mais garantir que os resultados serão consistentes; por exemplo, ao fazer interface com a linguagem C. A palavra-chave UNSAFEprefixada antes de INTERFACEou MODULE, pode ser usada para dizer ao compilador para habilitar certos recursos de baixo nível da linguagem. Por exemplo, uma operação insegura está contornando o sistema de tipos usando LOOPHOLEpara copiar os bits de um inteiro em um REALnúmero de ponto flutuante .

Uma interface que importa um módulo não seguro também deve ser insegura. Uma interface segura pode ser exportada por um módulo de implementação não seguro. Este é o uso típico ao fazer interface com bibliotecas externas , onde duas interfaces são construídas: uma não segura, a outra segura.

Genéricos

Uma interface genérica e seu módulo genérico correspondente, prefixam a palavra-chave INTERFACEou MODULEcom GENERICe tomam como argumentos formais outras interfaces. Assim (como os modelos C ++ ), pode-se facilmente definir e usar tipos de dados abstratos, mas ao contrário do C ++ , a granularidade está no nível do módulo. Uma interface é passada para a interface genérica e módulos de implementação como argumentos, e o compilador irá gerar módulos concretos.

Por exemplo, pode-se definir um GenericStack e, em seguida, instanciá-lo com interfaces como IntegerElem, ou RealElem, ou mesmo interfaces para objetos, desde que cada uma dessas interfaces defina as propriedades necessárias para os módulos genéricos.

Os tipos simples INTEGER, ou REALnão podem ser usados, porque não são módulos, e o sistema de genéricos é baseado no uso de módulos como argumentos. Por comparação, em um modelo C ++, um tipo simples seria usado.

ARQUIVO: IntegerElem.i3

 INTERFACE IntegerElem;
 CONST Name = "Integer";
 TYPE T = INTEGER;
 PROCEDURE Format(x: T): TEXT;
 PROCEDURE Scan(txt: TEXT; VAR x: T): BOOLEAN;
 END IntegerElem.

ARQUIVO: GenericStack.ig

 GENERIC INTERFACE GenericStack(Element);
 (* Here Element.T is the type to be stored in the generic stack. *)
 TYPE
    T = Public OBJECT;
    Public = OBJECT
    METHODS
        init(): TStack;
        format(): TEXT;
        isEmpty(): BOOLEAN;
        count(): INTEGER;
        push(elm: Element.T);
        pop(VAR elem: Element.T): BOOLEAN;
    END;
 END GenericStack.

ARQUIVO: GenericStack.mg

 GENERIC MODULE GenericStack(Element);
 < ... generic implementation details... >
 PROCEDURE Format(self: T): TEXT =
 VAR
    str: TEXT;
 BEGIN
    str := Element.Name & "Stack{";
    FOR k := 0 TO self.n -1 DO
        IF k > 0 THEN str := str & ", "; END;
            str := str & Element.Format(self.arr[k]);
    END;
    str := str & "};";
    RETURN str;
 END Format;
 < ... more generic implementation details... >
 END GenericStack.

ARQUIVO: IntegerStack.i3

INTERFACE IntegerStack = GenericStack(IntegerElem) END IntegerStack.

ARQUIVO: IntegerStack.m3

MODULE IntegerStack = GenericStack(IntegerElem) END IntegerStack.

Rastreabilidade

Qualquer identificador pode ser rastreado de volta ao local de origem, ao contrário do recurso 'incluir' de outras linguagens. Uma unidade compilada deve importar identificadores de outras unidades compiladas, usando uma IMPORTinstrução. Mesmo as enumerações usam a mesma notação de 'ponto' usada ao acessar um campo de um registro.

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.

Alocação dinâmica

Modula-3 suporta a alocação de dados em tempo de execução . Existem dois tipos de memória que podem ser alocados TRACEDe UNTRACED, a diferença é se o coletor de lixo pode vê-la ou não. NEW()é usado para alocar dados de qualquer uma dessas classes de memória. Em um UNSAFEmódulo, DISPOSEestá disponível para liberar memória não rastreada.

Orientado a Objeto

Técnicas de programação orientada a objetos podem ser usadas no Modula-3, mas seu uso não é necessário. Muitos dos outros recursos fornecidos no Modula-3 (módulos, genéricos) geralmente podem substituir a orientação a objetos.

O suporte a objetos é mantido intencionalmente em seus termos mais simples. Um tipo de objeto (denominado "classe" em outras linguagens orientadas a objetos) é introduzido com a OBJECTdeclaração, que tem essencialmente a mesma sintaxe de uma RECORDdeclaração, embora um tipo de objeto seja um tipo de referência, enquanto RECORDs em Modula-3 não são ( semelhantes às estruturas em C). Os tipos exportados geralmente são chamados de T por convenção e criam um tipo "Público" 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.

Isso define uma interface Personcom dois tipos, Te Public, que é definida como um objeto com dois métodos, getAge()e init(). Té definido como um subtipo de Publicpelo uso do <:operador.

Para criar um novo Person.Tobjeto, use o procedimento interno NEWcom o método init()como

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

A REVEALconstrução do Modula-3 fornece um mecanismo conceitualmente simples e limpo, mas muito poderoso para ocultar os detalhes de implementação dos clientes, com muitos níveis de facilidade arbitrariamente . Use REVEALpara mostrar a implementação completa da Personinterface de cima.

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.

Observe o uso da BRANDEDpalavra - chave, que "marca" os objetos para torná-los únicos, evitando a equivalência estrutural. BRANDEDtambém pode aceitar uma string como argumento, mas quando omitido, uma string exclusiva é gerada para você.

Modula-3 é uma das poucas linguagens de programação que requer referências externas de um módulo para ser estritamente qualificado. Ou seja, uma referência no módulo Aao objeto xexportado do módulo Bdeve assumir a forma B.x. No Modula-3, é impossível importar todos os nomes exportados de um módulo.

Por causa dos requisitos da linguagem sobre qualificação de nome e sobreposição de método , é impossível quebrar um programa de trabalho simplesmente adicionando novas declarações a uma interface (qualquer interface). Isso possibilita que programas grandes sejam editados simultaneamente por muitos programadores sem se preocupar com conflitos de nomenclatura; e também torna possível editar bibliotecas de linguagens centrais com o firme conhecimento de que nenhum programa existente será quebrado no processo.

Exceções

O tratamento de exceções é baseado em um sistema de TRY... EXCEPTbloco, que desde então se tornou comum. Um recurso que não foi adotado em outras linguagens, com as notáveis ​​exceções de Delphi , Python [1] , Scala [2] e Visual Basic.NET , é que a EXCEPTconstrução definiu uma forma de instrução switch com cada possível exceção como um caso em sua própria cláusula EXCEPT. Modula-3 também suporta uma construção LOOP... EXIT... ENDque faz um loop até que EXITocorra, uma estrutura equivalente a um loop simples dentro de uma cláusula TRY....EXCEPT

Multi-threaded

A linguagem suporta o uso de multi-threading e sincronização entre threads. Há um módulo padrão na biblioteca de tempo de execução ( m3core ) denominado Thread, que oferece suporte ao uso de aplicativos multithread. O tempo de execução do Modula-3 pode fazer uso de um thread separado para tarefas internas, como coleta de lixo.

Uma estrutura de dados embutida MUTEXé usada para sincronizar vários threads e proteger as estruturas de dados de acesso simultâneo com possível corrupção ou condições de corrida. A LOCKdeclaração introduz um bloco no qual o mutex está bloqueado. O desbloqueio de a MUTEXestá implícito na saída do bloco de execução do código. O MUTEXé um objeto e, como tal, outros objetos podem ser derivados dele.

Por exemplo, na seção de entrada / saída (I / O) da biblioteca libm3 , leitores e gravadores (Rd.T e Wr.T) são derivados de MUTEX e se bloqueiam antes de acessar ou modificar quaisquer dados internos, como buffers.

Resumo

Em resumo, o idioma apresenta:

Modula-3 é uma das raras linguagens cuja evolução de recursos é documentada.

Em Programação de Sistemas com Modula-3 , quatro pontos essenciais do projeto da linguagem são intensamente discutidos. Esses tópicos são: equivalência estrutural vs. nome, regras de subtipagem, módulos genéricos e modos de parâmetro como READONLY.

Recursos de biblioteca padrão

Continuando uma tendência iniciada com a linguagem C , muitos dos recursos necessários para escrever programas reais foram deixados de fora da definição da linguagem e, em vez disso, fornecidos por meio de um conjunto de bibliotecas padrão . A maioria das interfaces abaixo são descritas em detalhes em

Bibliotecas padrão que fornecem os seguintes recursos. Elas são chamadas de interfaces padrão e são obrigatórias (devem ser fornecidas) no idioma.

  • Texto: operações em referências de string imutáveis, chamadas TEXTs
  • Thread: Operações relacionadas a threading, incluindo MUTEXvariável de condição e pausa de thread. A biblioteca de threading fornece troca de threads preventiva
  • Word: operações bit a bit em inteiros sem sinal (ou palavras de máquina). Normalmente implementado diretamente pelo compilador
  • Interfaces de ponto flutuante

Algumas interfaces recomendadas implementadas nas implementações disponíveis, mas não são necessárias

  • Lex: Para analisar o número e outros dados
  • Fmt: formatação de vários tipos de dados para impressão
  • Pkl (ou Pickle): serialização de objetos de quaisquer tipos de referência acessíveis pelo coletor de lixo
  • Tabela: Módulos genéricos para mapas

Como em C, I / O também é fornecido por meio de bibliotecas, em Modula-3 chamado Rde Wr. O projeto orientado a objetos das bibliotecas Rd (leitores) e Wr (escritores) é abordado em detalhes no livro de Greg Nelson. Um aspecto interessante do Modula-3 é que ele é uma das poucas linguagens de programação cujas bibliotecas padrão foram formalmente verificadas para não conter vários tipos de bugs, incluindo bugs de bloqueio. Isso foi feito sob os auspícios do Larch / Modula-3 (ver família Larch ) e projetos de verificação estática estendida no DEC Systems Research Center .

Implementações

Vários compiladores estão disponíveis, a maioria deles de código aberto .

  • DEC-SRC M3, o original.
  • O kit de ferramentas Modula-3 do Olivetti Research Center (ORC), originalmente um compilador, agora está disponível como uma biblioteca para análise sintática, lexical e semântica de programas Modula-3.
  • Massa crítica CM3, um sucessor diferente do DEC-SRC M3
  • Polytechnique Montreal Modula-3 PM3, um sucessor do DEC-SRC M3, atualmente se fundindo com o CM3
  • EzM3, uma implementação independente leve e facilmente portável, desenvolvida em conexão com o CVSup
  • HM3, um sucessor do lançamento pm3-1.1.15 do PM3, com suporte para threading nativo usando NPTL
  • CM3, o sucessor do Critical Mass CM3. Esta é a única implementação atualizada, mantida e desenvolvida. As versões estão disponíveis em http://www.opencm3.net/releng/ .

Como o único aspecto das estruturas de dados C que está faltando no Modula-3 é o tipo de união, todas as implementações do Modula-3 existentes são capazes de fornecer boa compatibilidade de código binário com as declarações de tipo de linguagem C de matrizes e estruturas .

Livros

Nenhum desses livros ainda está sendo impresso, embora cópias usadas possam ser obtidas e alguns sejam digitalizados, parcial ou totalmente, e alguns capítulos de um deles tenham versões anteriores ou posteriores obtidas como relatórios de pesquisa na web.

  • Greg Nelson, ed., Systems Programming with Modula-3 A referência definitiva sobre a linguagem Modula-3 com artigos interessantes sobre construção de software de sistemas orientados a objetos e uma documentação da discussão conduzindo aos recursos finais da linguagem. Existem alguns anteriormente (ver para o capítulo dois, para o capítulo quatro, para o capítulo cinco, para o capítulo seis) e alguns posteriormente (ver para o capítulo um e mais atualizados dois, portanto, de ambas as versões anteriores da definição de linguagem e, para o capítulo três e para capítulo sete) de publicar versões da maioria de seus oito capítulos individualmente disponíveis no DEC Systems Research Center (SRC) anterior como relatórios de pesquisa para download.
  • Samuel P. Harbison, Modula-3 Livro de aula fácil de usar.
  • Robert Sedgewick , Algorithms in Modula-3
  • Laszlo Boszormenyi & Carsten Weich, Programming in Modula-3: An Introduction in Programming with Style
  • Renzo Orsini, Agostino Cortesi Programmare in Modula-3: introduzione alla programmazione imperativa e a oggetti um livro italiano da língua explicando suas principais características.

Projetos usando Modula-3

O software que é programado Modula-3 inclui:

  • O sistema operacional SPIN
  • O programa de sincronização do repositório de software CVSup
  • A linguagem Obliq , que usa objetos de rede Modula-3, tem a capacidade de migrar objetos em redes locais de forma transparente, permitindo uma capacidade distribuída para o paradigma de programação orientado a objetos Modula-3. Ele tem sido usado para construir aplicativos distribuídos, animações de computador e aplicativos de programação web na forma de extensão de script para Modula-3.

Influências em outras linguagens de programação

Embora o Modula-3 não tenha ganhado o status de mainstream, várias partes da distribuição do DEC-SRC M3 o fizeram. Provavelmente, a parte mais influente foi a biblioteca de objetos de rede, que formou a base para a primeira implementação de Remote Method Invocation (RMI) do Java, incluindo o protocolo de rede. Somente quando a Sun mudou do padrão Common Object Request Broker Architecture (CORBA) para o protocolo baseado em IIOP, ela foi abandonada. A documentação Java sobre coleta de lixo de objetos remotos ainda se refere ao trabalho pioneiro feito para Objetos de Rede Modula-3. A implementação de classes em Python também foi inspirada no mecanismo de classe encontrado em C ++ e Modula-3. Além disso, a linguagem Nim faz uso de alguns aspectos do Modula-3, como ponteiros rastreados e não rastreados .

Referências

links externos