Interpretado vs compilado: uma distinção útil?

29

Muitas perguntas são feitas aqui sobre implementos de linguagem interpretada versus compilada. Gostaria de saber se a distinção realmente faz algum sentido. (Na verdade, as perguntas são geralmente sobre idiomas, mas eles realmente estão pensando nas implementações mais populares desses idiomas).

Hoje quase nenhuma implementação é estritamente interpretada. ou seja, praticamente ninguém analisa e executa o código uma linha por vez. Além disso, a implementação compilada no código da máquina também está se tornando menos comum. Cada vez mais, os compiladores têm como alvo algum tipo de máquina virtual.

De fato, a maioria das implementações está convergindo para a mesma estratégia básica. O compilador produz bytecode que é interpretado ou compilado no código nativo via um JIT. É realmente uma mistura das idéias tradicionais de compilação e interpretação.

Assim, pergunto: Existe uma distinção útil entre implementações interpretadas e implementação compilada atualmente?

Winston Ewert
fonte
7
@DeadMG Não é tão novo quanto você pode pensar: Uma história breve do just-in-time ...
yannis
4
@DeadMG Dado que a maioria dos novos idiomas introduzidos nos últimos 10 anos é executada principalmente em algum tipo de VM, eu diria que ele tem razão. É claro que ainda existem (e ainda haverá décadas) linguagens compiladas no código nativo, e um JIT permanecerá luxuoso (ou não, se os caras do PyPy quiserem). Então, sim, possível exagero, mas eu concordo que o mainstream (por enquanto e no futuro previsível) parece ser o compilador de bytecode + possivelmente JIT.
4
@DeadMG, você deve ter uma longa barba branca, se o modelo da VM for "novo" para você. P-codefoi introduzido em 1966 primeiro. O IBM Aix existe desde 1986.
SK-logic
6
Coisas como conchas unix, Tcl e similares sempre seriam puramente interpretadas, de modo que a distinção faz sentido, pelo menos em um CS acadêmico. Mas é verdade que quando os codificadores estão murmurando sobre intérpretes versus compiladores, eles não fazem nenhum sentido na maioria dos casos.
SK-logic
3
@ SK-lógica, eu acho que o seu comentário é uma resposta melhor do que qualquer uma das respostas realmente postou
Winston Ewert

Respostas:

23

É importante lembrar que a interpretação e a compilação não são apenas alternativas uma da outra. No final, qualquer programa que você escreve (incluindo um compilado para o código da máquina) é interpretado. Interpretar código significa simplesmente pegar um conjunto de instruções e retornar uma resposta.

Compilar, por outro lado, significa converter um programa em um idioma para outro idioma. Geralmente, supõe-se que, quando a compilação ocorre, o código é compilado para uma linguagem de "nível inferior" (por exemplo, código de máquina, algum tipo de código de byte da VM, etc.). Esse código compilado ainda é interpretado posteriormente.

Com relação à sua pergunta sobre se existe uma distinção útil entre linguagens interpretadas e compiladas, minha opinião pessoal é que todos devem ter um entendimento básico do que está acontecendo com o código que escrevem durante a interpretação. Portanto, se seu código estiver sendo compilado por JIT, ou armazenado em cache por código de código etc., o programador deve ter pelo menos um entendimento básico do que isso significa.

Zach Smith
fonte
3
Sim, o programador deve ter um entendimento básico. Mas eu me pergunto se a terminologia compilada / interpretada não atrapalha isso.
Winston Ewert
2
Obrigado!! Interpretado é apenas um sinônimo de "executado", e é assim que todos os programas são executados.
gardenhead
9

A distinção é profundamente significativa porque as linguagens compiladas restringem a semântica de maneiras que as linguagens interpretadas não necessariamente. Algumas técnicas interpretativas são muito difíceis (praticamente impossíveis) de compilar.

O código interpretado pode fazer coisas como gerar código em tempo de execução e dar visibilidade a esse código nas ligações lexicais de um escopo existente. Esse é um exemplo. Outra é que os intérpretes podem ser estendidos com código interpretado, que pode controlar como o código é avaliado. Essa é a base dos antigos "fexprs" do Lisp: funções que são chamadas com argumentos não avaliados e decidem o que fazer com elas (tendo acesso total ao ambiente necessário para percorrer o código e avaliar variáveis, etc). Em linguagens compiladas, você não pode realmente usar essa técnica; você usa macros: funções chamadas em tempo de compilação com argumentos não avaliados e converte o código em vez de interpretar.

Algumas implementações de linguagem são construídas em torno dessas técnicas; seus autores rejeitam a compilação como um objetivo importante e adotam esse tipo de flexibilidade.

A interpretação sempre será útil como uma técnica para inicializar um compilador. Para um exemplo concreto, veja o CLISP (uma implementação popular do Common Lisp). O CLISP possui um compilador que é escrito por si só. Quando você cria o CLISP, esse compilador está sendo interpretado durante as etapas iniciais da construção. Ele é usado para se compilar e, depois de compilado, a compilação é feita usando o compilador compilado.

Sem um kernel de intérprete, você precisaria inicializar com algum Lisp existente, como o SBCL.

Com a interpretação, você pode desenvolver uma linguagem do zero absoluto, começando pela linguagem assembly. Desenvolva as rotinas básicas de E / S e núcleo e, em seguida, escreva uma linguagem de máquina ainda avaliada. Depois de avaliar, escreva na linguagem de alto nível; o kernel do código da máquina faz a avaliação. Use esse recurso para estender a biblioteca com muito mais rotinas e escreva um compilador também. Use o compilador para compilar essas rotinas e o próprio compilador.

Interpretação: um importante trampolim no caminho que leva à compilação!

Kaz
fonte
11
IMO, esta é a melhor resposta. Estou trabalhando na minha própria linguagem de brinquedos e o último parágrafo descreve a maneira como a estou desenvolvendo. Realmente facilita o trabalho em novas idéias. Também +1 por mencionar o processo de inicialização do CLISP.
sinan 11/07/2012
Em teoria, qualquer linguagem "interpretada" pode ser transformada em uma linguagem "compilada", gerando um arquivo EXE que consiste no intérprete mais o código-fonte ou código de código do programa interpretado. Pode não ser muito eficiente, no entanto.
Dan04 26/10/16
Leia como Wirth et al inventaram o código P para simplificar a transferência do PASCAL para novas arquiteturas de máquinas. Isso foi no início dos anos 1970.
John R. Strohm 26/10
11
Suspeito que seu parágrafo inicial confunda compilação e interpretação com comportamento estático e dinâmico, mas darei a você o benefício da dúvida e apenas pedirei um exemplo de uma linguagem com semântica que é "praticamente impossível" de compilar. Em relação à inicialização de um compilador, é verdade que a primeira implementação precisa ser escrita em algo que não seja o idioma que você está implementando, mas não precisa ser um intérprete, pode ser um compilador escrito em outro idioma.
precisa saber é o seguinte
1

Na verdade, muitas implementações de linguagens ainda são estritamente interpretadas; você pode simplesmente não estar ciente delas. Para citar alguns: as linguagens de shell do UNIX, o cmd do Windows e os shells do PowerScript, Perl, awk, sed, MATLAB, Mathematica e assim por diante.

Charles E. Grant
fonte
3
Acredito que o Perl é compilado internamente no bytecode e pelo menos o Mathematica pode ser compilado. E nada dita a implementação do awk e sed (acredito que alguns dos coreutils do GNU compilam expressões regulares para autômatos finitos antes da execução, o que os colocaria na categoria "compilar para a representação intermediária, interpretar isso").
11
Na verdade, tenho certeza de que Perl, MATLAB, Mathematica são todos compilados no bytecode. Eu não estou familiarizado com o PowerScript, você quer dizer Powershell? Nesse caso, usando o CLR e o bytecode.
Winston Ewert
@WinstonEwert, desculpe, eu quis dizer o PowerShell. Meu entendimento é que a tradução para uma forma intermediária não significa que algo não seja interpretado. Heck, o intérprete original do Dartmouth BASIC traduziu a fonte em tokens antes de interpretar. Cada uma das ferramentas que mencionei possui um modo em que 1) lê uma linha de origem, 2) converte essa linha em um formato executável (possivelmente algum código intermediário em vez de código nativo), 3) executa o código para essa linha, 4) volta para 1). Isso corresponde ao meu entendimento de um intérprete.
Charles E. Grant
2
Bytecode implica compilado. Um compilador de bytecode é simplesmente um programa que pega a fonte e a converte em bytecode. Portanto, todos os usos do bytecode devem envolver um compilador de bytecode. Mas o bytecode também deve ser interpretado (ou JITted). Portanto, qualquer coisa usando bytecode é um híbrido de intérprete / compilador.
Winston Ewert
4
Realmente, o que penso é que as pessoas lançam declarações como "python é interpretado" e "Java é compilado" sem entender as implementações. Estou perguntando se é útil descrever uma implementação nesses termos. A verdade geralmente é mais complicada e tentar resumir a interpretação / compilação não é útil.
Winston Ewert
1

Eu penso: Absolutamente sim .

De fato, a maioria das implementações está convergindo para a mesma estratégia básica

Realmente, o C ++ tem como objetivo portar para o domínio do compilador algum conceito de alto nível que geralmente é entregue aos intérpretes, mas permanece no lado minoritário ...

CapelliC
fonte
2
Aguarde até o Clang + LLVM se tornar a cadeia de ferramentas do compilador mais popular.
SK-logic
@ SK-logic, apesar do nome, acredito que Clang + LLVM produz código nativo.
Winston Ewert
11
@Winston Ewert, apenas se você quiser. Você pode parar no nível de IR do LLVM e fazer o que quiser com ele - interpretar, compilar com JIT, instrumentar da maneira que desejar. Você pode até traduzi-lo para Javascript e passar por um intérprete: github.com/kripken/emscripten/wiki
SK-logic
@ SK-logic, coisas legais! Não sabia que o LLVM poderia fazer isso.
Winston Ewert
11
A beleza do llvm é essa separação deliberada entre o front-end e o back-end. E as ferramentas para manipular o meio antes de direcionar o conjunto de instruções. Você pode mesclar todo o seu projeto no bytecode e, em seguida, otimizar a coisa toda; com outros compiladores, você precisará ter uma única fonte de arquivo ou pelo menos uma que inclua seu caminho pela árvore de fontes, para que o compilador atue em uma fonte combinada. Além disso, um conjunto de ferramentas sob o llvm é genérico para todos os destinos, você não precisa criar para cada destino, um compilador serve para todos (pelo menos no asm do destino).
old_timer
-1

Distinção útil: programas interpretados podem se modificar adicionando ou alterando funções em tempo de execução.

Diego Pacheco
fonte
8
Absurdo. O código de modificação automática (máquina) é o truque mais antigo do livro. Por outro lado, alguns argumentam que até o código nativo é finalmente interpretado por um intérprete convertido em silício (a CPU). Mas se assumirmos que todo o código é interpretado e não há distinção a fazer.
2
@delnan está certo. Vou apenas acrescentar que as línguas modernas podem modificar-se através da criação de novas classes de forma dinâmica e bibliotecas de carga / descarga (ou "assembléias" em .NET, por exemplo)
Jalayn
5
O Lisp comum é compilado, mas você ainda pode substituir as definições de função em tempo de execução facilmente.
SK-logic
Essa é uma característica realmente interessante e necessária (por exemplo, no Prolog) de interpretação.
CapelliC