Conheço o conceito de ortogonalidade, mas, do ponto de vista da linguagem de programação, existe uma maneira de verificar / provar?
Por exemplo, em C #, pode-se usar public
ou static
para uma assinatura de método. Você pode usar um ou ambos e eles não interferem um com o outro, então eles são ortogonais entre si, certo?
Minha pergunta é: como eu ligo para o restante dos recursos, principalmente os que não estão relacionados entre si?
Todos os recursos precisam coexistir / empilhar juntos?
Existe uma linguagem de programação 100% ortogonal?
c#
.net
programming-languages
language-design
Joan Venge
fonte
fonte
Respostas:
Não tenho certeza de que a ortogonalidade possa servir como métrica útil ou válida em caso de linguagens de ordem geral de uso geral como C #, porque exige a distinção de "operações" e "operandos" - as pequenas partes da linguagem que não são facilmente distinguível em idiomas de alta ordem como C #.
Meu entendimento da ortogonalidade é baseado na linguagem Assembler, em que a ortogonalidade do conjunto de instruções de uma determinada CPU ou microcontrolador indicava se existem algumas restrições nas operações executadas por essa CPU ou controlador, dependendo dos tipos de dados. Nos primeiros tempos, isso era importante, porque nem toda CPU suportava operações em números fracionários ou de tamanho diferente, etc.
A esse respeito, eu preferiria verificar a ortogonalidade da Common Intermediate Language usando a linguagem Stack Machine como o destino do compilador C #, não o próprio C #.
Se você está realmente interessado na ortogonalidade do C # e não me engano aqui (para qualquer finalidade), sugiro procurar alguns algoritmos de programação genética . Você pode usá-los para gerar programas diferentes do conjunto de palavras-chave fornecido (mesmo os sem sentido) e apenas verificar automaticamente se são compiláveis. Isso ajudaria você a ver automaticamente quais elementos da linguagem podem ser combinados e derivar alguns aspectos da sua métrica de ortogonalidade.
fonte
O termo "ortogonalidade" é um termo leigo para uma noção matemática precisa: os termos da linguagem formam uma álgebra inicial (consulte na Wikipedia).
Basicamente, significa "existe uma correspondência 1-1 entre sintaxe e significado". Isso significa: existe exatamente uma maneira de expressar as coisas e, se você pode colocar alguma expressão em um determinado local, também pode colocar qualquer outra expressão lá.
Outra maneira de pensar em "ortogonal" é que a sintaxe obedece ao princípio da substituição. Por exemplo, se você tiver uma instrução com um slot para uma expressão, qualquer expressão poderá ser colocada lá e o resultado ainda será um programa sintaticamente válido. Além disso, se você substituir
Quero enfatizar que "significado" não implica resultado computacional. Claramente, 1 + 2 e 2 + 1 são iguais a 3. No entanto, os termos são distintos e implicam um cálculo diferente, mesmo que tenha o mesmo resultado. O significado é diferente, assim como dois algoritmos de classificação são diferentes.
Você pode ter ouvido falar em "árvore de sintaxe abstrata" (AST). A palavra "abstrato" aqui significa precisamente "ortogonal". Tecnicamente, a maioria dos AST não é de fato abstrata!
Talvez você já tenha ouvido falar da linguagem de programação "C"? A notação de tipo C não é abstrata. Considerar:
Então, aqui está uma declaração de função retornando o tipo
int
. O tipo de um ponteiro para esta função é dado por:Note que você não pode escrever o tipo da função! A notação do tipo C é péssima! Não é abstrato. Não é ortogonal. Agora, suponha que desejemos criar uma função que aceite o tipo acima, em vez de int:
Tudo bem .. mas .. e se quisermos devolvê-lo:
Woops! Inválido. Vamos adicionar parênteses:
Woops! Isso também não funciona. Temos que fazer isso (é a única maneira!):
Agora está tudo bem, mas ter que usar um typedef aqui é ruim. C é péssimo. Não é abstrato. Não é ortogonal. Veja como você faz isso no ML, que é:
Condenamos C no nível da sintaxe.
Ok, agora vamos flogar C ++. Podemos corrigir a estupidez acima com modelos e obter uma notação de tipo ML (mais ou menos):
mas o sistema de tipos real é fundamentalmente falho por referências: se
T
é um tipo, então éT&
um tipo? A resposta é waffly: no nível da sintaxe, se você possui um tipo U = T &, então U & é permitido, mas significa apenas T &: uma referência a uma referência é a referência original. Isso é péssimo! Ele quebra o requisito de exclusividade semanticamente. Pior: T& & não é permitido sintaticamente: isso quebra o princípio da substituição. Portanto, as referências C ++ quebram a ortogonalidade de duas maneiras diferentes, dependendo do tempo de ligação (análise ou análise de tipo). Se você quer entender como fazer isso direito .. não há problema com ponteiros!Quase nenhuma linguagem real é ortogonal. Mesmo Scheme, que finge grande clareza de expressão, não é. No entanto, muitas linguagens boas podem ser consideradas como tendo "uma base razoavelmente próxima da característica ortogonal" e essa é uma boa recomendação para uma linguagem, aplicada tanto à sintaxe quanto à semântica subjacente.
fonte
int (*intintfunc())(int) { ... }
- intintfunc é uma função que não aceita argumentos e retorna um ponteiro para uma função que aceita 1 argumento int e retorna um valor int.Provar ortogonalidade é negativo. Isso significa que você não tem nenhuma construção que não seja ortogonal, o que significa que é muito mais fácil provar que algo não é ortogonal.
Na prática, a maioria das pessoas fala sobre a ortogonalidade das linguagens de programação em termos de graus, em vez de serem completamente ortogonais ou não. Quando o conhecimento de fazer algo em um contexto se traduz em outro contexto e "faz o que você espera", essa linguagem é considerada mais ortogonal. O LISP é considerado altamente ortogonal porque tudo é uma lista, mas não acho que se possa dizer que seja 100% ortogonal devido a algumas redundâncias que facilitam o uso. O C ++ é considerado não muito ortogonal, porque existem muitas "dicas" em que não funciona exatamente como você pensa.
fonte
Aviso, não sei nada sobre esse tópico.
Uma rápida olhada na Wikipedia parece indicar que a ortogonalidade é principalmente direcionada a padrões de design e sistemas. Em termos de linguagens de programação, a entrada indica que os conjuntos de instruções são ortogonais se houver uma e apenas uma instrução para cada ação possível, ou melhor, nenhuma instrução se sobrepõe a outra.
Para C #, eu imagino que seja ortogonal, pois a maioria dos truques de sintaxe (
foreach
vem à mente) são simplesmente front-ends para versões especialmente formadas da construção base (foreach
se transforma emfor
loops). No geral, o idioma apenas suporta realmente fazer as coisas de uma única maneira, mesmo que o açúcar sintático forneça maneiras adicionais de fazê-las. E, finalmente, tudo se compila atéMSIL
(ou como é chamado hoje em dia) eMSIL
provavelmente é ortogonal.Se você fizer uma ressalva de que o material sintático de açúcar é essencialmente um "invólucro" para fazê-lo da "maneira mais difícil", você pode analisar os vários recursos da linguagem, omitindo o açúcar, e ver se há alguma construção que realmente se sobreponha. Caso contrário, imagino que você possa declarar a linguagem ortogonal.
Meus dois centavos.
fonte
do...while
pode ser usado para fornecer o mesmo efeito quefor
? Eu nunca ouvi falar disso como sendo considerado açúcar sintático.do while
garante uma execução de loop único e verifica a condição após o fato.for
verifica a condição primeiro e não garante uma única execução.Você continua fazendo o que está fazendo, enumerando todas as combinações que funcionam ou são proibidas.
Isso é tudo. É muito doloroso de fazer.
Se todos os recursos puderem ser particionados em subconjuntos disjuntos que não interfiram entre si, é claro que tudo seria sensato.
Todas as estruturas de dados funcionam com todos os tipos primitivos. Todos os operadores de expressão trabalham com todos os tipos. Essas são definições comuns de ortogonalidade. Mas você pode querer mais (ou menos)
Às vezes, no entanto, há casos especiais devido a sistemas operacionais ou bibliotecas herdadas que não são ortogonais.
Além disso, alguns tipos não são realmente muito conformáveis. Por exemplo, o Python permite comparar dois objetos de dicionário para "fazer pedidos". Mas quase não existe uma definição sensata de "ordenação" entre os dicionários. Python define um, mas é bastante discutível. Esse caso especial faz com que os dicionários falhem em um teste de ortogonalidade?
Quão ortogonal é "ortogonal o suficiente"? O que você precisa ver para se sentir feliz com o grau de ortogonalidade no seu idioma.
fonte
A lista de recursos não-ortogonais é realmente longa na maioria das linguagens de programação, por exemplo
Esses são apenas alguns que me vêm à mente, mas existem muitos outros, e também em outros idiomas.
É difícil garantir que não haja interferência sutil entre os recursos do idioma. Como CAR Hoare indica em seu artigo "Hints on Programming Language Design":
Provavelmente, uma boa jogada para aumentar a ortogonalidade é unificar conceitos (que vai na direção da resposta de @ karl-bielfeld). Se tudo estiver, digamos, uma lista ou um objeto, as chances são de que haverá menos conflitos. Ou, em vez de aninhar a classe após uma reflexão, torne-a um dos principais recursos.
A maioria dos documentos sobre linguagens de programação prova certas propriedades da linguagem (por exemplo, solidez do tipo) em um subconjunto (um "núcleo") da linguagem formalizada. Aqui devemos fazer o oposto, provar que todos os recursos são compostos com segurança. Além disso, isso significa que se deve definir o que significa "compor". Isso significa "correr"? (Nesse caso, o link acima sobre o case de borda com digitação estática e dinâmica é seguro). Isso significa ser "seguro"? Isso significa ser previsível do ponto de vista do desenvolvedor?
Tudo isso é muito interessante - mas também muito desafiador.
fonte