Por que os compiladores de hospedagem automática são considerados um rito de passagem para novos idiomas?

30

Já ouvi em vários lugares agora que as pessoas esperam que os idiomas usem, ou pelo menos tenham, um compilador auto-hospedado para merecer respeito.

Estou curioso para saber por que isso acontece. Um compilador parece ser um software muito significativo para escrever, e imagino que nem todos os idiomas sejam adequados para criá-los. Não faria mais sentido gastar o esforço trabalhando em algo que trará melhores resultados?

Chris Cooper
fonte
17
"Um compilador parece ser um software muito significativo para escrever, e eu imagino que nem todas as linguagens são adequadas para criá-las.": Eu consideraria essa uma boa razão para tentar escrever um compilador em uma nova linguagem, a saber para provar que o idioma está à altura da tarefa.
Giorgio
13
A menos que seja uma linguagem de propósito especial, uma linguagem que não seja adequada para escrever um compilador provavelmente também não é adequada para o que eu quero fazer.
CodesInChaos
3
AFAIK, isso nem sempre é verdade para o Fortran. Vários compiladores Fortran (por exemplo, gfortrando GCC ...) não são codificados no Fortran.
Basile Starynkevitch 25/11

Respostas:

29

Não faria mais sentido gastar o esforço trabalhando em algo que trará melhores resultados?

Como o quê?

O bom dos compiladores é que eles não têm muitas dependências. Isso os torna bons candidatos para um novo idioma que provavelmente ainda não possui uma biblioteca padrão muito grande ou diversificada.

Melhor ainda, eles exigem uma variedade de coisas, além de serem bem estudados. A variedade ajuda a garantir que seu exemplo teste várias partes do idioma. Ser bem estudado significa que você tem outros compiladores para comparar - além de dar mais credibilidade aos tipos acadêmicos que sabe o que está fazendo.

E embora os compiladores pareçam muito trabalho, eles são bem pequenos no grande esquema das coisas. Se os implementadores de linguagem não conseguem nem fazer algo que já fizeram antes na nova linguagem, como vão fazer coisas novas? Como eles lidam com coisas realmente grandes, como bibliotecas padrão ou um IDE?

Telastyn
fonte
Apenas como uma observação lateral, eu gostaria de mencionar que, apesar de ser legal, ainda existem vários motivos pelos quais um compilador pode ser escrito em outro idioma. Por exemplo, a maioria dos mecanismos javascript não são escritos em javascript. Há muitas razões para isso: integração com outro software, vinculação a bibliotecas / dependências existentes, ferramentas superiores, desempenho, código legado ... Às vezes, a autocompilação da linguagem é boa, mas ainda faz sentido manter o compilador principal em outro. No entanto, a linguagem por si só faz sentido. Normalmente, você normalmente não pode se permitir reconstruir um ecossistema inteiro.
dagnelies
2
@arnaud E o fato de um compilador Javascript exigir um ambiente Javascript, que não pode ser escrito em Javascript porque o Javascript requer um ambiente Javascript, <repita paradoxalmente> , porque um ambiente Javascript não é fornecido pelo sistema operacional (e se foi, não seria escrito em Javascript).
Qix
3
@Qix en.wikipedia.org/wiki/Bootstrapping_%28compilers%29 Mas principalmente não há razão para usá-lo. É amplamente conhecido como um idioma ruim, os navegadores se esquecem de não usá-lo para compilação porque estão no controle da situação :), enquanto o resto de nós não tem escolha na web.
Den
3
Não tenho tanta certeza sobre a afirmação "não tenho muitas dependências". Isso pode ser verdade para o front-end do compilador . Porém, assim que você tiver um AST, lançar seu próprio otimizador e gerador de código não parecerá uma rota promissora. Além do fato de que as técnicas modernas de otimização exigem mecanismos lógicos formais sofisticados para os quais se pode querer usar uma biblioteca de terceiros, não há razão para reinventar a roda para cada novo idioma, em vez de se basear em uma base de força do setor como o GCC ou LLVM.
5gon12eder
30

O objetivo de ter um compilador no idioma que está sendo compilado costuma fazer parte da prática de " comer sua própria comida de cachorro ". Isso demonstra ao mundo que você considera o idioma, o compilador e o ecossistema dos módulos e ferramentas de suporte "bons o suficiente para trabalhos sérios" ou "prontos para produção".

Ele também tem o efeito virtuoso de forçar os mais próximos ao design de linguagem, compilador e tempo de execução a enfrentar diretamente os efeitos de todas as decisões que eles tomaram e as prioridades de desenvolvimento que eles escolheram - warts e tudo. Isso geralmente leva a um grupo principal que não apenas entende o ambiente da linguagem na teoria, mas que possui uma vasta experiência prática usando a linguagem / ferramentas no crisol de condições difíceis e com palavras reais.

Jonathan Eunice
fonte
11
para completar: comer sua própria comida de cachorro ; veja dog fed (adj.) ou dogfooding (verbo)
Qix
17

As pessoas criam novas linguagens de uso geral por um motivo principal: elas odeiam pelo menos uma coisa sobre todas as outras línguas por aí. É por isso que tantas línguas não decolam. Você tem uma ótima idéia para uma linguagem que melhoraria sua vida de programação, mas precisa fazer a primeira implementação em uma linguagem que o incomode de pelo menos uma maneira. Auto-hospedagem significa que você não precisa mais trabalhar nessa antiga linguagem irritante. É por isso que os criadores de uma linguagem trabalham nessa etapa e a veem como um marco importante.

Muitos recursos de linguagem ficam bem no papel, mas quando você os usa em um projeto real, começa a ver suas limitações. Por exemplo, muitos idiomas não têm suporte unicode decente no início. A conclusão de um grande projeto ajuda a garantir que muitos desses tipos de situações tenham sido encontrados e tratados, e um compilador auto-hospedado é um projeto tão bom quanto qualquer outro. É por isso que outras pessoas que não os criadores da linguagem o veem como um marco importante.

Isso não significa que é o único marco a ser observado. Há funcionalidades que não são exercidas por um compilador, como integração de banco de dados, interfaces gráficas, rede etc.

Karl Bielefeldt
fonte
Eu sinto que um idioma (nativo) é um idioma em que ele pode se compilar e um kernel Linux pode ser portado para ele (uma vez que abrange a maioria / todas as tarefas necessárias para a maioria dos sistemas operacionais modernos).
Qix
Porém, não é realmente necessário um suporte decente a Unicode para escrever um compilador.
Paŭlo Ebermann 4/16
11

Steve Yegge escreveu um ótimo post que, de maneira indireta, trata disso.

Grande ponto # 1: os compiladores abrangem praticamente todos os aspectos da ciência da computação. Eles são um curso de nível superior, porque você precisa saber todas as outras coisas que aprender no currículo de ciências da computação apenas para começar. Estruturas de dados, pesquisa e classificação, desempenho assintótico, coloração de gráficos? Está tudo lá.

Há uma razão pela qual Knuth trabalha em sua monumental (e interminável) "Art of Computer Programming" há várias décadas, mesmo que tenha começado como (apenas) um livro de compilador. Da mesma forma que Carl Sagan disse: "Se você deseja fazer uma torta de maçã a partir do zero, você deve primeiro inventar o universo"; se você deseja escrever um compilador, deve primeiro lidar com quase todos os aspectos da ciência da computação.

Isso significa que, se o compilador for auto-hospedado, certamente será capaz de fazer o que eu preciso, não importa o que eu esteja fazendo. Por outro lado, se você não escreveu um compilador em seu idioma, há uma boa chance de ele perder algo realmente importante para alguém, porque os implementadores de idiomas nunca precisaram escrever um programa que exigisse que pensassem em todos esses problemas.

Grande ponto # 2: de 30.000 pés, um número surpreendente de problemas se parece com compiladores.

Os compiladores pegam um fluxo de símbolos, descobrem sua estrutura de acordo com algumas regras predefinidas específicas do domínio e os transformam em outro fluxo de símbolos. Parece bastante geral, não é? Bem, sim.

Quer você esteja na equipe do Visual C ++ ou não, muitas vezes você precisará fazer algo que pareça parte de um compilador. Eu faço isso literalmente todos os dias.

Ao contrário da maioria das outras profissões, os programadores não usam apenas ferramentas, mas constroem suas próprias ferramentas. Um programador que não puder (devido à falta de habilidade ou falta de ferramentas utilizáveis ​​com as quais construir outras ferramentas) escreverá ferramentas para sempre será prejudicado, limitado às ferramentas fornecidas por outra pessoa.

Se um idioma "não é adequado para criar" programas que podem receber um fluxo de símbolos, aplicando regras a eles e transformá-lo em outro fluxo de símbolos, isso soa como um idioma bastante limitado e não seria útil para mim.

(Felizmente, acho que não existem muitas linguagens de programação inadequadas para transformar símbolos. C é provavelmente uma das piores linguagens usadas atualmente, mas os compiladores C geralmente são auto-hospedados, de modo que nunca impediram ninguém.)

Uma terceira razão pela qual terminarei, por experiência pessoal, não mencionada por Yegge (porque ele não estava escrevendo sobre "por que se auto-hospedar"): elimina erros. Quando você está escrevendo um compilador, isso significa que toda vez que você o compila (não apenas toda vez que o executa ), depende dele para funcionar e funcionar corretamente em uma base de código de tamanho decente (o próprio compilador).

Este mês, estou usando um compilador não hospedado relativamente novo e famoso (você provavelmente pode adivinhar qual) e não posso passar dois dias sem segfaulting a coisa. Eu me pergunto o quanto os designers realmente tiveram que usá-lo.

DefinitelyNotSteve
fonte
8

Se você deseja que um compilador para o idioma X seja auto-hospedado, primeiro é necessário implementá-lo em outro idioma, por exemplo, Y, de modo que ele aceite a linguagem X e cuspa código de montagem, ou algum código intermediário, ou até código de objeto para a máquina na qual o compilador está sendo executado. Você deseja escolher o idioma Y para ser o mais semelhante possível ao idioma X, pois em algum momento você traduzirá o código escrito em Y para X.

Mas você não deseja escrever mais do compilador na linguagem Y do que o necessário; portanto, para começar, você implementa apenas um subconjunto da linguagem, eliminando construções redundantes. No caso de uma linguagem do tipo 'C', while mas no for or do while . se não houver caso ou operação terciária. Nenhuma estrutura ou união ou enumeração. Etc. O que resta é apenas o idioma suficiente para escrever um analisador e um gerador de código rudimentar para o idioma X. Em seguida, verifique a saída. Novamente.

Depois de ter esse trabalho, você pode reescrever a fonte do compilador que foi escrita no idioma Y para o idioma X e compilar a fonte do idioma X usando o compilador escrito no idioma Y. A saída será um novo compilador escrito no novo idioma X que compila a linguagem X, ou seja, agora é auto-hospedada. No entanto, ele não está completo, pois você implementou apenas um subconjunto do idioma no idioma Y.

Então agora você adiciona os recursos ausentes, testando cada um (ou grupo de recursos) para que eles gerem o código correto. ou seja, uma vez que o recurso seja implementado no compilador, você pode escrever programas de teste usando o (s) novo (s) recurso (s), compilar e testá-los, mas ainda não deve usá-los na fonte do compilador. Depois que os novos recursos são verificados, você pode usá-los na própria fonte do compilador - talvez substituindo parte do código original escrito no subconjunto de idiomas - recompile a fonte do compilador usando a versão com os novos recursos.

Agora você tem um mecanismo para adicionar novos recursos ao idioma - e, uma vez que a geração de código para os recursos foi verificada correta, eles podem ser usados ​​na próxima geração do próprio compilador.

Há 60 anos atrás, quando os computadores chegaram pela primeira vez (e mais tarde quando os microprocessadores chegaram), não havia outros idiomas Y adequados para a implementação do compilador inicial. Portanto, os primeiros compiladores precisavam ser escritos em código de montagem e, quando o compilador estivesse em execução, o código de montagem seria substituído pela versão escrita em nova linguagem. Nenhum montador também? O processador inteiro caiu para outro nível, com o montador sendo inicialmente escrito em código de máquina .

tcrosley
fonte
2

É possível produzir uma linguagem de programação que não seja bem projetada para escrever um compilador, mas seja bem projetada para algum outro propósito?

Olhando para uma linguagem como SQL, suponho que a resposta seja sim. Mas línguas dessa natureza não são de propósito geral.

Jaydee
fonte
11
Desafio aceito: escreva um compilador C no SQL.
Qix
2

Quem diz isso? ... de qualquer forma, é apenas uma opinião. Alguns podem concordar, outros podem não, não há certo ou errado aqui. Alguns idiomas têm compiladores escritos em si, outros não. Tanto faz.

No entanto, acho que é um bom exercício / prova de conceito se uma linguagem é capaz de "se auto-compilar" ... é simplesmente ... legal ... e prova que a linguagem é adequada para fazer coisas complexas.

Eu também gostaria de mencionar que, apesar de ser legal, ainda existem vários motivos pelos quais um compilador pode ser escrito em outro idioma. Por exemplo, a maioria dos mecanismos javascript não são escritos em javascript. Há muitas razões para isso: integração com outro software, vinculação a bibliotecas / dependências existentes, ferramentas superiores, desempenho, código legado ... Às vezes, a autocompilação da linguagem é boa, mas ainda faz sentido manter o compilador principal em outro. No entanto, a linguagem por si só faz sentido. Normalmente, você normalmente não pode se permitir reconstruir um ecossistema inteiro.

dagnelies
fonte
2

Clang é escrito em C ++. Não seria muito difícil reescrever o compilador Clang Objective-C no Objective-C, mas seria inútil. Qualquer alteração no compilador C ++ teria que ser refeita no Objective-C e vice-versa. Então por que?

Agora existe um compilador Clang Swift. Certamente esse compilador pode ser reescrito no Swift. Mas qual seria esse objetivo? Para demonstrar que a linguagem é poderosa o suficiente para escrever nele um compilador? Ninguém se importa se você pode escrever compiladores no Swift. As pessoas não se importam se você pode escrever interfaces de usuário no Swift, e você comprovadamente pode.

Se você possui um compilador bem testado que pode ser facilmente adaptado para compilar idiomas diferentes, não faz sentido reescrevê-lo em idiomas diferentes, a menos que a reescrita em um idioma diferente facilite o trabalho com o compilador. E se faria sentido escrever Clang no Swift, por exemplo, os compiladores Clang C, C ++ e Objective-C seriam todos escritos no Swift.

Há coisas mais importantes a fazer do que provar que você pode escrever um compilador em alguma linguagem de programação.

gnasher729
fonte
1

Isso mostra que o idioma é capaz de processar processamento complexo de cadeias e traduzir para outro idioma / interpretar a si próprio.

No processo de criação de um compilador (o primeiro grande projeto), haverá problemas que surgirão.

catraca arrepiante
fonte