Dylan (linguagem de programação) - Dylan (programming language)

Dylan
Dylan logo.png
Paradigma multiparadigma : funcional , orientado a objetos
Desenvolvedor Comunidade de código aberto Apple Computer , Harlequin , Carnegie Mellon University
Apareceu pela primeira vez 1992 ; 29 anos atrás ( 1992 )
Versão estável
2020.1 / 10 de outubro de 2020 ; 8 meses atrás ( 2020-10-10 )
Disciplina de digitação Forte, dinâmico
Plataforma IA-32 , x86-64
SO Plataforma cruzada
Extensões de nome de arquivo Dylan
Local na rede Internet opendylan .org
Implementações principais
Dylan aberto , Gwydion Dylan
Dialetos
infixo-dylan (também conhecido como Dylan), prefixo-dylan (também conhecido como Lisp)
Influenciado por
CLOS , ALGOL , Scheme , EuLisp
Influenciado
Lasso , Python , Ruby , Julia

Dylan é uma linguagem de programação multiparadigma que inclui suporte para programação funcional e orientada a objetos (OOP) e é dinâmica e reflexiva, enquanto fornece um modelo de programação projetado para dar suporte à geração de código de máquina eficiente, incluindo controle refinado sobre comportamentos dinâmicos e estáticos . Foi criado no início dos anos 1990 por um grupo liderado pela Apple Computer .

Uma visão geral concisa e completa da linguagem pode ser encontrada no Manual de Referência Dylan.

Dylan deriva de Scheme e Common Lisp e adiciona um sistema de objetos integrado derivado do Common Lisp Object System (CLOS). Em Dylan, todos os valores (incluindo números, caracteres, funções e classes ) são objetos de primeira classe . Dylan suporta herança múltipla , polimorfismo , envio múltiplo , argumentos de palavra-chave , introspecção de objeto, macros de extensão de sintaxe baseada em padrão e muitos outros recursos avançados. Os programas podem expressar controle refinado sobre o dinamismo, admitindo programas que ocupam um continuum entre a programação dinâmica e estática e apoiando o desenvolvimento evolutivo (permitindo a prototipagem rápida seguida de refinamento e otimização incrementais).

O principal objetivo do design de Dylan é ser uma linguagem dinâmica adequada para o desenvolvimento de software comercial . Dylan tenta resolver problemas de desempenho em potencial introduzindo limites "naturais" para a flexibilidade total dos sistemas Lisp , permitindo ao compilador entender claramente as unidades compiláveis, como bibliotecas .

Dylan deriva muito de sua semântica de Scheme e outros Lisps; algumas implementações de Dylan foram inicialmente construídas dentro de sistemas Lisp existentes. No entanto, Dylan tem uma sintaxe semelhante a ALGOL em vez de uma sintaxe de prefixo semelhante a Lisp.

História

Dylan foi criado no início dos anos 1990 por um grupo liderado pela Apple Computer . Em um momento de seu desenvolvimento, ele foi planejado para uso com o computador Apple Newton , mas a implementação de Dylan não atingiu maturidade suficiente a tempo, e Newton, em vez disso, usou uma combinação de C e NewtonScript desenvolvida por Walter Smith. A Apple encerrou seu esforço de desenvolvimento Dylan em 1995, embora tenha disponibilizado uma versão de "lançamento de tecnologia" (Apple Dylan TR1) que incluía um ambiente de desenvolvimento integrado avançado (IDE).

Dois outros grupos contribuíram para o design da linguagem e implementações desenvolvidas: Harlequin lançou um IDE comercial para Microsoft Windows e Carnegie Mellon University lançou um compilador de código aberto para sistemas Unix chamado Gwydion Dylan. Ambas as implementações agora são de código aberto. A implementação do Harlequin agora é chamada de Open Dylan e é mantida por um grupo de voluntários, os Dylan Hackers.

A linguagem Dylan recebeu o codinome de Ralph. James Joaquin escolheu o nome Dylan para "DYnamic LANguage".

Sintaxe

Muitos dos recursos de sintaxe de Dylan vêm de sua herança Lisp. Originalmente, Dylan usava uma sintaxe de prefixo semelhante ao Lisp, que era baseada em expressões s . No momento em que o design da linguagem foi concluído, a sintaxe foi alterada para uma sintaxe semelhante ao ALGOL, com a expectativa de que seria mais familiar para um público mais amplo de programadores. A sintaxe foi projetada por Michael Kahl. Ele é descrito em detalhes no Manual de Referência Dylan.

Sintaxe lexical

Dylan não faz distinção entre maiúsculas e minúsculas . A sintaxe lexical de Dylan permite o uso de uma convenção de nomenclatura onde os sinais de subtração de hífen são usados ​​para conectar as partes de identificadores de várias palavras (às vezes chamados de " lisp-case " ou " kebab case "). Essa convenção é comum em linguagens Lisp, mas não pode ser usada em linguagens de programação que tratam qualquer hífen-menos que não faça parte de um literal numérico como um único token léxico , mesmo quando não estiver rodeado por caracteres de espaço em branco .

Além de caracteres alfanuméricos e sinais de subtração de hífen, Dylan permite certos caracteres não alfanuméricos como parte de identificadores. Os identificadores não podem consistir nesses caracteres não alfanuméricos ou apenas em caracteres numéricos. Se houver alguma ambigüidade, o espaço em branco será usado.

Código de exemplo

Uma aula simples com vários slots:

define class <point> (<object>)
  slot point-x :: <integer>,
    required-init-keyword: x:;
  slot point-y :: <integer>,
    required-init-keyword: y:;
end class <point>;

Por convenção, as classes são nomeadas com sinais de menor que e maior que usados ​​como colchetes angulares , por exemplo, a classe nomeada <point>no exemplo de código.

Em end class <point>ambos classe <point>são opcionais. Isso é verdadeiro para todas as endcláusulas. Por exemplo, você pode escrever end ifou apenas endencerrar uma ifdeclaração.

A mesma aula, reescrita da maneira mais mínima possível:

define class <point> (<object>)
  slot point-x;
  slot point-y;
end;

Os slots agora são digitados como <object>. Os slots devem ser inicializados manualmente.

Por convenção, os nomes de constantes começam com "$":

define constant $pi :: <double-float> = 3.1415927d0;

Uma função fatorial:

define function factorial (n :: <integer>) => (n! :: <integer>)
  case
    n < 0     => error("Can't take factorial of negative integer: %d\n", n);
    n = 0     => 1;
    otherwise => n * factorial(n - 1);
  end
end;

Aqui, n!e <integer>são apenas identificadores normais.

Não há declaração de retorno explícita . O resultado de um método ou função é a última expressão avaliada. É um estilo comum deixar de fora o ponto-e-vírgula após uma expressão na posição de retorno.

Módulos vs. namespace

Em muitas linguagens orientadas a objetos, as classes são os principais meios de encapsulamento e modularidade; cada classe define um namespace e controla quais definições são visíveis externamente. Além disso, as classes em muitas linguagens definem uma unidade indivisível que deve ser usada como um todo. Por exemplo, o uso de uma Stringfunção de concatenação requer a importação e a compilação de todos os String.

Algumas linguagens, incluindo Dylan, também incluem um namespace explícito separado ou sistema de módulo que executa o encapsulamento de uma maneira mais geral.

Em Dylan, os conceitos de unidade de compilação e unidade de importação são separados, e as classes não têm nada a ver especificamente com nenhum dos dois. Uma biblioteca define itens que devem ser compilados e manipulados juntos, enquanto um módulo define um namespace. As classes podem ser colocadas juntas em módulos, ou cortadas entre eles, como o programador desejar. Freqüentemente, a definição completa de uma classe não existe em um único módulo, mas está espalhada por vários que são opcionalmente reunidos. Programas diferentes podem ter definições diferentes da mesma classe, incluindo apenas o que eles precisam.

Por exemplo, considere uma biblioteca complementar para suporte a regexString . Em alguns idiomas, para que a funcionalidade seja incluída em strings, a funcionalidade deve ser adicionada ao Stringnamespace. Assim que isso ocorre, a Stringclasse se torna maior e as funções que não precisam usar regex ainda devem "pagar" por isso em um tamanho de biblioteca maior. Por esse motivo, esses tipos de add-ons são normalmente colocados em seus próprios namespaces e objetos. A desvantagem dessa abordagem é que as novas funções não fazem mais parte do String ; em vez disso, ele é isolado em seu próprio conjunto de funções que devem ser chamadas separadamente. Em vez de myString.parseWith(myPattern), que seria a organização natural do ponto de vista OO, algo como myPattern.parseString(myString)é usado, o que efetivamente inverte a ordem.

Em Dylan, muitas interfaces podem ser definidas para o mesmo código, por exemplo, o método de concatenação String pode ser colocado na interface String e na interface "concat" que reúne todas as diferentes funções de concatenação de várias classes. Isso é mais comumente usado em bibliotecas matemáticas, onde as funções tendem a ser aplicáveis ​​a tipos de objetos amplamente diferentes.

Um uso mais prático da construção de interface é construir versões públicas e privadas de um módulo, algo que outras linguagens incluem como um recurso bolt on que invariavelmente causa problemas e adiciona sintaxe. Em Dylan, cada chamada de função pode ser simplesmente colocada na interface "Privada" ou "Desenvolvimento" e coletar funções publicamente acessíveis em Public. Em Java ou C ++, a visibilidade de um objeto é definida no código, o que significa que, para suportar uma mudança semelhante, um programador seria forçado a reescrever totalmente as definições e não poderia ter duas versões ao mesmo tempo.

Aulas

As classes em Dylan descrevem slots(membros de dados, campos, ivars, etc.) de objetos de uma forma semelhante à maioria das linguagens OO. Todos os acessos aos slots são por meio de métodos, como em Smalltalk . Os métodos getter e setter padrão são gerados automaticamente com base nos nomes dos slots. Em contraste com a maioria das outras linguagens OO, outros métodos aplicáveis ​​à classe são frequentemente definidos fora da classe e, portanto, as definições de classe em Dylan normalmente incluem a definição do armazenamento apenas. Por exemplo:

define class <window> (<view>)
  slot title :: <string> = "untitled", init-keyword: title:;
  slot position :: <point>, required-init-keyword: position:;
end class;

Neste exemplo, a classe " <window>" é definida. A sintaxe da <nome da classe> é apenas uma convenção, para fazer os nomes das classes se destacarem - os colchetes angulares são apenas parte do nome da classe. Em contraste, em alguns idiomas, a convenção é colocar a primeira letra do nome da classe em maiúscula ou prefixar o nome com um C ou T (por exemplo). <window>herda de uma única classe <view>,, e contém dois slots, titlesegurando uma string para o título da janela e positionsegurando um ponto XY para um canto da janela. Neste exemplo, o título recebeu um valor padrão, enquanto a posição não. A sintaxe opcional init-keyword permite que o programador especifique o valor inicial do slot ao instanciar um objeto da classe.

Em linguagens como C ++ ou Java, a classe também definiria sua interface. Neste caso, a definição acima não possui instruções explícitas, então em ambas as linguagens o acesso aos slots e métodos é considerado protected, o que significa que eles podem ser usados ​​apenas por subclasses. Para permitir que código não relacionado use as instâncias de janela, elas devem ser declaradas public.

Em Dylan, esses tipos de regras de visibilidade não são considerados parte do código, mas do sistema de módulo / interface. Isso adiciona flexibilidade considerável. Por exemplo, uma interface usada durante o desenvolvimento inicial pode declarar tudo público, enquanto uma usada em testes e implantação pode limitar isso. Com C ++ ou Java, essas mudanças exigiriam mudanças no código-fonte, então as pessoas não o farão, enquanto em Dylan esse é um conceito totalmente não relacionado.

Embora este exemplo não o use, Dylan também oferece suporte a herança múltipla .

Métodos e funções genéricas

Em Dylan, os métodos não estão intrinsecamente associados a nenhuma classe específica; os métodos podem ser considerados como existentes fora das classes. Assim como o CLOS, o Dylan é baseado em despacho múltiplo (multimétodos), onde o método específico a ser chamado é escolhido com base nos tipos de todos os seus argumentos. O método não precisa ser conhecido em tempo de compilação, entendendo-se que a função requerida pode estar disponível, ou não, com base nas preferências do usuário.

Em Java, os mesmos métodos seriam isolados em uma classe específica. Para usar essa funcionalidade, o programador é forçado a importar essa classe e referir-se a ela explicitamente para chamar o método. Se essa classe não estiver disponível ou for desconhecida no momento da compilação, o aplicativo simplesmente não compilará.

Em Dylan, o código é isolado do armazenamento nas funções . Muitas classes têm métodos que chamam suas próprias funções, parecendo e se sentindo como a maioria das outras linguagens OO. No entanto, o código também pode estar localizado em funções genéricas , o que significa que não estão anexados a uma classe específica e podem ser chamados nativamente por qualquer pessoa. Vincular uma função genérica específica a um método em uma classe é realizado da seguinte maneira:

define method turn-blue (w :: <window>)
  w.color := $blue;
end method;

Essa definição é semelhante às de outras linguagens e provavelmente seria encapsulada na <window>classe. Observe a chamada: = setter, que é o açúcar sintático para color-setter($blue, w).

A utilidade dos métodos genéricos vem à tona quando você considera exemplos mais "genéricos". Por exemplo, uma função comum na maioria das linguagens é o to-string, que retorna alguma forma legível para o objeto. Por exemplo, uma janela pode retornar seu título e sua posição entre parênteses, enquanto uma string retorna a si mesma. Em Dylan, esses métodos podem ser todos reunidos em um único módulo chamado " to-string", removendo, assim, esse código da definição da própria classe. Se um objeto específico não oferecer suporte a to-string, ele pode ser facilmente adicionado ao to-stringmódulo.

Extensibilidade

Todo esse conceito pode parecer muito estranho para alguns leitores. O código a ser manipulado to-stringpor uma janela não está definido em <window>? Isso pode não fazer sentido até que você considere como Dylan lida com a chamada do to-string. Na maioria das linguagens, quando o programa é compilado, o to-stringfor <window>é procurado e substituído por um ponteiro (mais ou menos) para o método. Em Dylan, isso ocorre quando o programa é executado pela primeira vez; o tempo de execução constrói uma tabela de detalhes de nome de método / parâmetros e procura métodos dinamicamente por meio dessa tabela. Isso significa que uma função para um método específico pode estar localizada em qualquer lugar, não apenas na unidade de tempo de compilação. No final, o programador recebe uma flexibilidade considerável em termos de onde colocar seu código, coletando-o ao longo das linhas de classe onde apropriado e nas linhas funcionais onde não é.

A implicação aqui é que um programador pode adicionar funcionalidade às classes existentes definindo funções em um arquivo separado. Por exemplo, você pode desejar adicionar a verificação ortográfica a todos os <string>s, o que na maioria das linguagens exigiria acesso ao código-fonte da classe string - e essas classes básicas raramente são fornecidas na forma original. Em Dylan (e outras "linguagens extensíveis"), o método de verificação ortográfica pode ser adicionado ao spell-checkmódulo, definindo todas as classes nas quais ele pode ser aplicado por meio da define methodconstrução. Nesse caso, a funcionalidade real pode ser definida em uma única função genérica, que pega uma string e retorna os erros. Quando o spell-checkmódulo é compilado em seu programa, todas as strings (e outros objetos) obterão a funcionalidade adicionada.

Apple Dylan

Apple Dylan é a implementação de Dylan produzida pela Apple Computer . Foi originalmente desenvolvido para o produto Apple Newton .

Referências

links externos