A diferença entre um compilador e um intérprete
On Dezembro 31, 2021 by adminDe acordo com suas definições, a diferença entre um compilador e um intérprete parece suficientemente clara:
- interprete é um programa que executa diretamente instruções escritas em uma linguagem de programação
- compilador é um programa que transforma o código fonte em uma linguagem de baixo(er)-nível
Se você aprofundar mais, no entanto, você encontrará alguma indefinição entre os dois.
Na verdade um intérprete poderia traduzir a linguagem do código fonte de uma forma intermediária, para acelerar a execução. É o que normalmente acontece com um idioma que depende de uma máquina virtual. Isto naturalmente leva a algumas questões:
Todos os idiomas que utilizam uma máquina virtual são interpretados?
Todas elas são realmente compiladas?
Você pode dizer ambas: uma linguagem é primeiro compilada em uma forma/língua intermediária e depois essa coisa intermediária é interpretada em tempo de execução. O que também leva a outro problema, um compilador e um intérprete não devem ser pensados como um programa, mas mais como um grupo de programas, um sistema. O que você, como usuário, pensa como um compilador, pode na verdade incluir mais de um programa. Por exemplo, ele pode incluir um linker: um programa que combina diferentes arquivos objeto em um arquivo, para que ele possa ser mais facilmente utilizado. Algo semelhante poderia ser dito de um interpretador.
Can You Tell Me Everything About Compilers & Interpreters?
So, quais são todas as peças que compõem um compilador ou um interpretador? Você poderia procurar uma resposta precisa e técnica para tais perguntas na academia. Ou pode encontrar discussões sobre estas questões no StackOverflow.
O que realmente importa para nós como desenvolvedores, ou mesmo para nós como criadores de uma linguagem, é quais são as diferenças no trabalho com eles. Ambos têm vantagens e desvantagens, e de facto algumas línguas podem ter tanto um intérprete como um compilador, ou mais do que um. É isso que vamos ver.
O ponto principal ainda permanece: um intérprete executa o código agora, um compilador prepara o código fonte para uma execução que vem depois. Todas as diferenças práticas derivam destes diferentes objetivos.
Como Distribui um Programa
Em termos práticos uma diferença importante é que um compilador gera um programa independente, enquanto um programa interpretado sempre precisa do interpretador para executar.
Após você ter um programa compilado, você pode executá-lo sem precisar instalar mais nada. Isto simplifica a distribuição. Por outro lado, o executável trabalha em uma plataforma específica: diferentes sistemas operacionais e diferentes processadores precisam de diferentes versões compiladas. Por exemplo, um programa C++ compilado pode funcionar em um computador com um processador x86, mas não um com um chip ARM. Ou pode funcionar em um sistema Linux, mas não em um Windows.
Se você vai interpretar um programa, você pode distribuir a mesma cópia para usuários em plataformas diferentes. No entanto, eles precisarão de um intérprete que funcione na sua plataforma específica. Você pode distribuir o código fonte original ou uma forma intermediária. Uma forma intuitiva de olhar para um intérprete é esta: é como a função eval
em JavaScript. Funciona onde quer que o JavaScript funcione, mas precisa de um intérprete JavaScript para que a plataforma seja executada.
Suporte para plataformas cruzadas
Esta é uma diferença técnica que leva a importantes consequências reais: é mais fácil fazer programas multi-plataforma com uma linguagem de programação interpretada.
Isso porque, na maioria das vezes, você está apenas criando um programa para a plataforma do intérprete. Será o próprio intérprete que o traduzirá na forma adequada para a plataforma real (por exemplo, Windows/Linux e x86/ARM). É claro que ainda existem algumas diferenças em cada plataforma das quais você deve estar ciente. Um exemplo comum é o caractere separador de directório.
Quando compila um programa, em vez disso, precisa de ter cuidado com todas as pequenas diferenças entre cada plataforma. Isto acontece em parte porque as linguagens compiladas tendem a ser de baixo(er) nível, como por exemplo C++, por isso dão-lhe menos acesso ao sistema e portanto mais responsabilidade. Mas outra razão é que todas as bibliotecas que você está usando precisam de si mesmas para suportar diferentes plataformas. Portanto, se elas não suportam Windows, você não pode suportar Windows.
Speed Has Multiple Faces
Again, no caso da velocidade, temos uma espécie de paradoxo: um compilador é mais rápido e mais lento que um intérprete. Muitas pessoas sabem que um programa compilado é muito mais rápido que um programa interpretado, mas isto não é o quadro completo. Um programa compilado é mais rápido de executar do que um programa interpretado, mas leva mais tempo para compilar e executar um programa do que apenas interpretá-lo.
Um compilador de fato produz programas mais rápidos. Isso acontece fundamentalmente porque ele deve analisar cada declaração apenas uma vez, enquanto um interpretador deve analisá-la a cada vez. Além disso, um compilador pode otimizar o código executável que ele produz. Isto é porque ele sabe exatamente onde vai rodar e também porque leva tempo para otimizar o código. Tempo que tornaria a interpretação muito lenta.
Runtime Speed Versus Development Speed
Você pode pensar que isto é uma picareta: se você compilar um programa ele roda mais rápido, o tempo que ele leva para compilar não importa. Esta é normalmente a opinião da velha escola. E sem dúvida o programa resultante é executado mais vezes do que é compilado. Então, quem se importa se o desenvolvimento leva mais tempo? Bem, com certeza é necessária uma atitude de “trazer a dor” ao desenvolvimento que é algo admirável. Mas e se os ganhos em tempo de execução não forem relevantes, enquanto as perdas em produtividade de desenvolvimento são significativas?
É uma coisa se você criar um sistema operacional e outra se você fizer um aplicativo auto-selfie. Mesmo seus usuários podem preferir uma perda não perceptível na velocidade do tempo de execução, em troca de obter recursos mais rapidamente. Não há uma resposta de tamanho único: em alguns contextos a produtividade é mais importante que a velocidade, em outros o contrário é verdadeiro.
The Mysteries Of Debugging
Há outro aspecto particular que acaba sendo mais incerto do que o que se poderia considerar: o debugging. A depuração no papel é mais fácil quando se usa um intérprete do que quando se usa um compilador. Isto é verdade por várias razões:
- com o intérprete há uma versão do executável; você não precisa de uma versão de depuração para o desenvolvimento e uma de lançamento para o usuário final
- há menos bugs específicos da plataforma usando um interpretador
- desde que o interpretador transforme o código na mosca, a informação do código fonte ainda está disponível
- como o intérprete executa uma declaração de cada vez, é mais fácil encontrar um erro
A diferença que as ferramentas de desenvolvimento fazem
Embora tudo isto seja verdade na prática, isto pode ser menos relevante do que parece. Na verdade, se você pensar em sua experiência, você provavelmente descobriria que depurar JavaScript é mais difícil do que depurar C++. Por que isso acontece? Em parte é o design das próprias linguagens. O JavaScript usa a digitação dinâmica, enquanto o C++ usa a digitação estática. Esta última facilita a captura de erros mais cedo. Mas, no final das contas, trata-se das ferramentas de desenvolvimento. Compilar o C++ à mão é difícil, por isso a maioria das pessoas usa IDEs para desenvolver com ele. Por outro lado, você pode facilmente usar o editor de texto e as ferramentas de linha de comando para desenvolver em JavaScript.
Isso significa que, em termos práticos, se você desenvolver com C++, você também pode depurar C++. Em vez disso, você pode desenvolver com JavaScript sem saber como fazer a depuração adequada em JavaScript.
Dizendo que, se os colocarmos no mesmo contexto, cada um com um ótimo IDE e ferramentas de suporte, a situação volta ao normal. Na verdade, muitos ambientes interpretados são usados por pessoas que querem aprender a usar uma nova linguagem. É mais fácil testar, e encontrar o que está certo e errado, olhando o que acontece linha por linha e em tempo real.
Sumário
Vimos as principais diferenças que importam entre um compilador e um intérprete. Mais importante ainda, vimos que as consequências das diferentes filosofias são mais importantes do que as técnicas. Em suma, há culturas que vêm com certas escolhas técnicas que acabam por ser relevantes por si só. Se você quer velocidade e facilidade de desenvolvimento você vai escolher todas as tecnologias para velocidade e não apenas uma. E os seus utilizadores vão seguir o seu exemplo.
Este é um aspecto crucial a ter em conta, especialmente se quiser criar a sua própria linguagem de programação. Rasmus Lerdorf criou PHP para ser fácil de usar. E na verdade foi incrivelmente mais fácil de usar comparado com as alternativas, pelo menos no momento de sua criação. Mas ele começou mais como uma biblioteca do que como uma linguagem. E embora tenha melhorado muito, ainda sofre com o seu início. Você ainda pode criar bom código PHP, mas menos usuários do que de costume o fazem. Porque se você só precisa de algo que funcione, segurança, manutenção, etc., todo o resto vem depois.
Se você quiser saber como você pode praticamente construir um intérprete ou um compilador para a sua linguagem, você pode querer dar uma olhada nos recursos para criar uma linguagem de programação. Se você quer aprender isso, e tudo o que você precisa para criar sua própria linguagem, você só precisa escolher um ótimo livro, amado tanto por crianças quanto por adultos, sobre como criar linguagens pragmáticas e leves.
5 coisas para acertar ao construir uma linguagem
Receba a lista de verificação por email e obtenha mais dicas sobre como construir linguagens
Deixe uma resposta