Gostaria de saber se é possível construir compiladores para linguagens dinâmicas como Ruby para ter desempenho semelhante e comparável ao C / C ++? Pelo que entendi sobre compiladores, como o Ruby, por exemplo, compilar código Ruby nunca pode ser eficiente, porque a maneira como o Ruby lida com reflexão, recursos como a conversão automática de tipo de número inteiro para número inteiro grande e a falta de digitação estática tornam a construção de um compilador eficiente para Ruby extremamente difícil.
É possível criar um compilador que possa compilar Ruby ou qualquer outra linguagem dinâmica em um binário com desempenho muito próximo ao C / C ++? Existe uma razão fundamental para os compiladores JIT, como PyPy / Rubinius, eventualmente ou nunca corresponderem a C / C ++ no desempenho?
Nota: Entendo que o “desempenho” pode ser vago; portanto, para esclarecer isso, eu quis dizer, se você pode fazer X em C / C ++ com desempenho Y, você pode fazer X em Ruby / Python com desempenho próximo a Y? Onde X é tudo, desde drivers de dispositivo e código do SO até aplicativos da web.
fonte
Respostas:
Para todos aqueles que disseram "sim", vou oferecer um contraponto de que a resposta é "não", por padrão . Esses idiomas nunca poderão corresponder ao desempenho de idiomas compilados estaticamente.
Kos ofereceu o argumento (muito válido) de que as linguagens dinâmicas têm mais informações sobre o sistema em tempo de execução, que podem ser usadas para otimizar o código.
No entanto, existe outro lado da moeda: essas informações adicionais precisam ser mantidas em sigilo. Nas arquiteturas modernas, isso é um fator que mata o desempenho.
William Edwards oferece uma boa visão geral do argumento .
Em particular, as otimizações mencionadas por Kos não podem ser aplicadas além de um escopo muito limitado, a menos que você limite o poder expressivo de seus idiomas de maneira bastante drástica, como mencionado por Devin. É claro que isso é uma troca viável, mas, para o bem da discussão, você acaba com uma linguagem estática , não dinâmica. Essas linguagens diferem fundamentalmente de Python ou Ruby, como a maioria das pessoas as entenderia.
William cita alguns slides interessantes da IBM :
Algumas dessas verificações podem ser eliminadas após a análise (Nota: essa análise também leva tempo - em tempo de execução).
Além disso, Kos argumenta que as linguagens dinâmicas podem até superar o desempenho do C ++. O JIT pode realmente analisar o comportamento do programa e aplicar otimizações adequadas.
Mas os compiladores C ++ podem fazer o mesmo! Os compiladores modernos oferecem a chamada otimização guiada por perfil que, se receberem uma entrada adequada, pode modelar o comportamento do tempo de execução do programa e aplicar as mesmas otimizações que um JIT aplicaria.
Obviamente, tudo isso depende da existência de dados de treinamento realistas e, além disso, o programa não pode adaptar suas características de tempo de execução se o padrão de uso mudar no meio da execução. JITs podem teoricamente lidar com isso. Eu ficaria interessado em ver como isso se sai na prática, pois, para alternar otimizações, o JIT precisaria coletar continuamente dados de uso que mais uma vez atrasam a execução.
Em resumo, não estou convencido de que as otimizações de hot spot de tempo de execução superem a sobrecarga de rastrear informações de tempo de execução a longo prazo , em comparação com a análise e otimização estáticas.
fonte
javac
alguma vez a otimização guiada por perfil? Não tanto quanto eu sei. Em geral, não faz sentido otimizar o compilador de uma linguagem JIT, uma vez que a JIT pode lidar com ela (e, no mínimo, desta forma, mais linguagens lucram com o esforço). Então (compreensivelmente) nunca houve muito esforço nojavac
otimizador, tanto quanto eu sei (para as linguagens .NET isso é definitivamente verdade).Sim. Tome, como exemplo, o PyPy. É uma coleção de código Python que executa perto de C ao interpretar (nem tanto assim, mas também não tão longe). Ele faz isso através da realização de análises em programa completo no código fonte para atribuir cada variável um tipo estático (ver a Annotator e Rtyper docs para mais detalhes), e então, uma vez armado com a mesma informação do tipo que você dá C, ele pode executar a mesma tipos de otimizações. Pelo menos em teoria.
A desvantagem, é claro, é que apenas um subconjunto de código Python é aceito pelo RPython e, em geral, mesmo que essa restrição seja levantada, apenas um subconjunto de código Python pode se sair bem: o subconjunto que pode ser analisado e receber tipos estáticos.
Se você restringir o Python o suficiente, poderão ser criados otimizadores que tirem proveito do subconjunto restrito e o compilem em código eficiente. Este não é realmente um benefício interessante, na verdade, é bem conhecido. Mas o ponto principal de usar Python (ou Ruby) em primeiro lugar era que queríamos usar recursos interessantes que talvez não analisem bem e resultem em bom desempenho! Então a pergunta interessante é realmente ...
Nah.
Com o que quero dizer: claro, talvez à medida que o código seja acumulado, você possa obter informações de digitação e pontos de acesso suficientes para compilar todo o código até o código da máquina. E talvez possamos obter um desempenho melhor que C para algum código. Eu não acho isso extremamente controverso. Mas ainda precisa "aquecer", e o desempenho ainda é um pouco menos previsível, e não será tão bom quanto o C ou C ++ para determinadas tarefas que exigem um desempenho consistente e previsível.
Os dados de desempenho existentes para Java, que possuem mais informações de tipo que Python ou Ruby, e um compilador JIT melhor desenvolvido que Python ou Ruby, ainda não correspondem ao C / C ++. É, no entanto, no mesmo estádio.
fonte
A resposta curta é: não sabemos , pergunte novamente em 100 anos. (Ainda podemos não saber então; possivelmente nunca saberemos.)
Em teoria, isso é possível. Pegue todos os programas já escritos, traduza-os manualmente para o código de máquina mais eficiente possível e escreva um intérprete que mapeie os códigos-fonte para os códigos de máquina. Isso é possível, pois apenas um número finito de programas já foi gravado (e, à medida que mais programas são gravados, mantenha as traduções manuais). Isso também é, obviamente, completamente idiota em termos práticos.
Por outro lado, teoricamente, linguagens de alto nível podem conseguir o desempenho do código de máquina, mas não o superam. Isso ainda é muito teórico, porque, em termos práticos, raramente recorremos à escrita de código de máquina. Esse argumento não se aplica à comparação de linguagens de nível superior: não implica que C deva ser mais eficiente que Python, apenas esse código de máquina não pode ser pior que Python.
Vindo do outro lado, em termos puramente experimentais, podemos ver que na maioria das vezes , as linguagens de alto nível interpretadas apresentam desempenho pior do que as linguagens de baixo nível compiladas. Tendemos a escrever código não sensível ao tempo em linguagens de alto nível e loops internos críticos no assembly, com linguagens como C e Python entrando no meio. Embora eu não tenha nenhuma estatística para apoiar isso, acho que essa é realmente a melhor decisão na maioria dos casos.
No entanto, existem instâncias incontestadas em que linguagens de alto nível superam o código que seria gravado realisticamente: ambientes de programação para fins especiais. Programas como Matlab e Mathematica costumam ser muito melhores na solução de certos tipos de problemas matemáticos do que o que meros mortais podem escrever. As funções da biblioteca podem ter sido escritas em C ou C ++ (que é um combustível para o campo “linguagens de baixo nível são mais eficientes”), mas isso não é da minha conta se estou escrevendo código do Mathematica, a biblioteca é uma caixa preta.
É teoricamente possível que o Python se aproxime, ou talvez até mais, do desempenho ideal que o C? Como visto acima, sim, mas estamos muito longe disso hoje. Por outro lado, os compiladores fizeram muito progresso nas últimas décadas, e esse progresso não está diminuindo.
Linguagens de alto nível tendem a automatizar mais as coisas, por isso têm mais trabalho a executar e, portanto, tendem a ser menos eficientes. Por outro lado, eles tendem a ter mais informações semânticas, portanto, pode ser mais fácil detectar otimizações (se você estiver escrevendo um compilador Haskell, não precisa se preocupar que outro segmento modifique uma variável sob o seu nariz). Um dos vários esforços para comparar diferentes linguagens de programação de
maçãs e laranjasé o Computer Benchmark Game (anteriormente conhecido como shootout). Fortran tende a brilhar em tarefas numéricas; mas quando se trata de manipular dados estruturados ou comutação de encadeamento de alta taxa, F # e Scala se saem bem. Não tome esses resultados como evangelho: muito do que eles estão medindo é quão bom o autor do programa de testes em cada idioma foi.Um argumento a favor de linguagens de alto nível é que o desempenho em sistemas modernos não está tão fortemente correlacionado com o número de instruções executadas, e menos com o tempo. Linguagens de baixo nível são boas correspondências para máquinas sequenciais simples. Se um idioma de alto nível executar duas vezes mais instruções, mas conseguir usar o cache de maneira mais inteligente, de maneira que ele faça a metade do número de erros de cache, poderá ser o vencedor.
Nas plataformas de servidor e desktop, as CPUs quase atingiram um platô em que não ficam mais rápidas (as plataformas móveis também estão chegando lá); isso favorece linguagens em que o paralelismo é fácil de explorar. Muitos processadores passam a maior parte do tempo aguardando uma resposta de E / S; o tempo gasto em computação é pouco comparado com a quantidade de E / S, e uma linguagem que permite ao programador minimizar as comunicações é uma vantagem.
Em suma, enquanto os idiomas de alto nível começam com uma penalidade, eles têm mais espaço para melhorias. Quão perto eles podem chegar? Pergunte novamente em 100 anos.
Nota final: frequentemente, a comparação não é entre o programa mais eficiente que pode ser escrito na língua A e o mesmo na linguagem B, nem entre o programa mais eficiente já escrito em cada idioma, mas entre o programa mais eficiente que pode ser escrito por um ser humano em um determinado período de tempo em cada idioma. Isso introduz um elemento que não pode ser analisado matematicamente, mesmo em princípio. Em termos práticos, isso geralmente significa que o melhor desempenho é um compromisso entre quanto código de baixo nível você precisa escrever para atingir as metas de desempenho e quanto código de baixo nível você tem tempo para escrever para cumprir as datas de lançamento.
fonte
A diferença básica entre a declaração C ++
x = a + b
e a declaração Pythonx = a + b
é que um compilador C / C ++ pode dizer a partir desta declaração (e um pouco de informação extra que ela tem prontamente disponíveis sobre os tipos dex
,a
eb
) precisamente o código de máquina precisa ser executado . Considerando que, para dizer quais operações a instrução Python vai fazer, é necessário resolver o Problema da Parada.Em C, essa instrução basicamente será compilada para um dos poucos tipos de adição de máquina (e o compilador C sabe qual). No C ++, ele pode ser compilado dessa maneira, ou pode ser chamado para chamar uma função estaticamente conhecida ou (no pior caso) pode ser necessário compilar para uma consulta e chamada de método virtual, mas mesmo isso tem uma sobrecarga de código de máquina bastante pequena. Mais importante, porém, o compilador C ++ pode dizer dos tipos estaticamente envolvidos envolvidos se pode emitir uma única operação de adição rápida ou se precisa usar uma das opções mais lentas.
Em Python, teoricamente, um compilador poderia fazer quase esse bem se soubesse disso
a
eb
fosse ambosint
. Há alguma sobrecarga adicional de boxe, mas se os tipos forem estaticamente conhecidos, você provavelmente poderá se livrar disso também (enquanto ainda apresenta a interface que números inteiros são objetos com métodos, hierarquia de superclasses, etc.). O problema é que um compilador para Python não podesaiba disso, porque as classes são definidas em tempo de execução, podem ser modificadas em tempo de execução e até os módulos que definem e importam são resolvidos em tempo de execução (e mesmo quais instruções de importação são executadas depende de coisas que só podem ser conhecidas em tempo de execução). Portanto, o compilador Python precisaria saber qual código foi executado (por exemplo, resolver o problema da parada) para saber o que a instrução que ele está compilando fará.Portanto, mesmo com as análises mais sofisticadas teoricamente possíveis , você simplesmente não pode dizer muito sobre o que uma determinada instrução Python fará antes do tempo. Isso significa que, mesmo que um compilador Python sofisticado fosse implementado, em quase todos os casos ainda seria necessário emitir código de máquina que segue o protocolo de pesquisa de dicionário do Python para determinar a classe de um objeto e encontrar métodos (percorrendo o MRO da hierarquia de classes, que também pode mudar dinamicamente no tempo de execução e, portanto, é difícil compilar em uma tabela de método virtual simples) e basicamente fazer o que os intérpretes (lentos) fazem. É por isso que não há realmente nenhum compilador de otimização sofisticado para linguagens dinâmicas. Não é apenas difícil criar um, o máximo retorno possível não é '
Observe que isso não se baseia no que o código está fazendo, mas no que o código poderia estar fazendo. Mesmo o código Python, que é uma série simples de operações aritméticas inteiras, deve ser compilado como se estivesse invocando operações de classe arbitrárias. Linguagens estáticas têm maiores restrições sobre as possibilidades do que o código poderia estar fazendo e, conseqüentemente, seus compiladores podem fazer mais suposições.
Os compiladores JIT ganham com isso esperando até o tempo de execução compilar / otimizar. Isso os permite emitir um código que funciona para o que o código está fazendo e não para o que poderia estar fazendo. E por causa disso, os compiladores JIT têm um retorno potencial muito maior para linguagens dinâmicas do que para linguagens estáticas; para linguagens mais estáticas, muito do que um otimizador gostaria de saber pode ser conhecido com antecedência, portanto é melhor otimizar isso, deixando menos para um compilador JIT.
Existem vários compiladores JIT para linguagens dinâmicas que pretendem atingir velocidades de execução comparáveis às do C / C ++ compilado e otimizado. Existem até otimizações que podem ser feitas por um compilador JIT que não pode ser feito por um compilador antecipado para qualquer idioma; portanto, teoricamente, a compilação JIT (para alguns programas) poderia um dia superar o melhor compilador estático possível. Porém, como Devin apontou corretamente, as propriedades da compilação JIT (somente os "pontos de acesso" são rápidos e somente após um período de aquecimento) significa que é improvável que as linguagens dinâmicas compiladas por JIT sejam adequadas para todas as aplicações possíveis, mesmo que se tornem mais rápido ou mais rápido que os idiomas compilados estaticamente em geral.
fonte
foo = x + y
que a previsão do comportamento do operador de adição no tempo de compilação depende da solução do problema de parada.x + y
operações eficientes de adição de máquina, é necessário saber em tempo de compilação se é ou não. O tempo todo , não apenas o tempo todo. Para linguagens dinâmicas, isso quase nunca é possível com programas realistas, embora heurísticas razoáveis achem acertadas a maior parte do tempo. A compilação requer garantias em tempo de compilação . Então, falando sobre "em muitas circunstâncias", na verdade você não está respondendo à minha resposta.Apenas um ponteiro rápido que descreve o pior cenário possível para linguagens dinâmicas:
Como conseqüência, o Perl (completo) nunca pode ser compilado estaticamente.
Em geral, como sempre, depende. Estou confiante de que, se você tentar emular recursos dinâmicos em uma linguagem compilada estaticamente, interpretadores bem concebidos ou variantes (parcialmente) compiladas poderão se aproximar ou diminuir o desempenho de linguagens compiladas estaticamente.
Outro ponto a ser lembrado é que as linguagens dinâmicas resolvem outro problema que não o C. C é pouco mais que uma sintaxe agradável para o assembler, enquanto as linguagens dinâmicas oferecem abstrações ricas. O desempenho do tempo de execução geralmente não é a principal preocupação: o tempo de colocação no mercado, por exemplo, depende da capacidade de seus desenvolvedores criarem sistemas complexos e de alta qualidade em curtos prazos. Extensibilidade sem recompilação, por exemplo, com plugins, é outro recurso popular. Qual idioma você prefere nesses casos?
fonte
Na tentativa de oferecer uma resposta mais objetivamente científica a essa questão, defendo o seguinte. Uma linguagem dinâmica requer que um intérprete, ou tempo de execução, tome decisões em tempo de execução. Esse intérprete, ou tempo de execução, é um programa de computador e, como tal, foi escrito em alguma linguagem de programação, estática ou dinâmica.
Se o intérprete / tempo de execução foi escrito em uma linguagem estática, pode-se escrever um programa nessa linguagem estática que (a) desempenha a mesma função que o programa dinâmico que ele interpreta e (b) executa pelo menos também. Felizmente, isso é evidente, pois fornecer uma prova rigorosa dessas reivindicações exigiria um esforço adicional (possivelmente considerável).
Supondo que essas afirmações sejam verdadeiras, a única saída é exigir que o intérprete / tempo de execução também seja escrito em uma linguagem dinâmica. No entanto, encontramos o mesmo problema de antes: se o intérprete é dinâmico, é necessário um intérprete / tempo de execução, que também deve ter sido escrito em uma linguagem de programação, dinâmica ou estática.
A menos que você assuma que uma instância de um intérprete é capaz de se interpretar em tempo de execução (espero que isso seja evidentemente absurdo), a única maneira de superar linguagens estáticas é que cada instância de intérprete seja interpretada por uma instância de intérprete separada; isso leva a uma regressão infinita (espero que isso seja evidentemente absurdo) ou a um ciclo fechado de intérpretes (espero que isso também seja evidentemente absurdo).
Parece, então, que mesmo em teoria, as linguagens dinâmicas podem ter um desempenho melhor do que as linguagens estáticas, em geral. Ao usar modelos de computadores realistas, parece ainda mais plausível; afinal, uma máquina pode executar apenas seqüências de instruções da máquina e todas as seqüências de instruções da máquina podem ser compiladas estaticamente.
Na prática, combinar o desempenho de uma linguagem dinâmica com uma linguagem estática pode exigir a reimplementação do intérprete / tempo de execução em uma linguagem estática; no entanto, o fato de você poder fazer isso é o ponto crucial deste argumento. É uma questão de galinha e ovo e, desde que você concorde com as suposições não comprovadas (embora, na minha opinião, principalmente evidentes) feitas acima, podemos realmente respondê-la; temos que concordar com as linguagens estáticas, não dinâmicas.
Outra maneira de responder à pergunta, à luz dessa discussão, é a seguinte: no programa armazenado, controle = modelo de dados da computação, que está no coração da computação moderna, a distinção entre compilação estática e dinâmica é uma falsa dicotomia; linguagens estaticamente compiladas devem ter um meio de gerar e executar código arbitrário em tempo de execução. Está fundamentalmente relacionado à computação universal.
fonte
main(args) { for ( i=0; i<1000000; i++ ) { if ( args[0] == "1" ) {...} else {...} }
pode acelerar significativamente quando o valor deargs
é conhecido (assumindo que ele nunca muda, o que podemos afirmar). Um compilador estático não pode criar código que elimine a comparação. (É claro que, nesse exemplo que você acabou de puxar oif
fora do circuito Mas a coisa pode ser mais complicado..)Eu acho que a resposta é "sim" . Eu também acredito que eles podem até superar a arquitetura C / C ++ atual em termos de eficiência (mesmo que ligeiramente).
O motivo é simples: há mais informações em tempo de execução do que em tempo de compilação.
Tipos dinâmicos são apenas um pequeno obstáculo: se uma função é sempre ou quase sempre executada com os mesmos tipos de argumentos, um otimizador JIT pode gerar um código de máquina e ramificação para esse caso específico. E há muito mais que pode ser feito.
Veja Dynamic Languages Strike Back , um discurso de Steve Yegge, do Google (também há uma versão em vídeo em algum lugar em que acredito). Ele menciona algumas técnicas concretas de otimização de JIT da V8. Inspirador!
Estou ansioso pelo que teremos nos próximos 5 anos!
fonte
Pessoas que aparentemente pensam que isso é teoricamente possível, ou em um futuro distante, estão completamente erradas na minha opinião. O ponto reside no fato de que as linguagens dinâmicas fornecem e impõem um estilo de programação totalmente diferente. Na verdade, a diferença é dupla, mesmo se os dois aspectos estiverem inter-relacionados:
O segundo ponto fornece genericidade gratuitamente. Observe que as estruturas aqui são elementos compostos, coleções, mas também os próprios tipos, e até rotinas (!) De todos os tipos (funções, ações, operações) ... Poderíamos digitar estruturas por seus tipos de elementos, mas devido ao primeiro ponto o verificação aconteceria em tempo de execução de qualquer maneira. Poderíamos ter digitado símbolos e ainda ter estruturado aqueles não digitados de acordo com seus tipos de elementos (uma matriz
a
seria apenas digitada como uma matriz e não como uma matriz de ints), mas mesmo essas poucas não são verdadeiras em uma linguagem dinâmica (tambéma
poderiam conter uma linha).O melhor desempenho que podemos obter na programação dinâmica é, na minha opinião, equivalente ao seguinte: implementar em C o modelo de uma linguagem dinâmica, vamos chamá-lo de , isto é, um tipo de máquina fictícia ou uma biblioteca de tempo de execução completa. E, em seguida, programe (em C diretamente) usando apenas o modelo, sem recursos simples de C. Isso significa ter:L
Element
, que inclui anotações do tipo (ou uma referência à representação real do tipo de no modelo)LElement
, eles podem conter elementos de qualquer tipoEstá claro para mim que isso é apenas uma enorme penalidade de perf; e eu nem toco todas as consequências (a miríade de verificações de tempo de execução de todos os tipos necessários para garantir a sensibilidade do programa) bem descritas em outras postagens.
fonte
Não tive tempo de ler todas as respostas em detalhes ... mas fiquei divertido.
Houve uma controvérsia semelhante nos anos sessenta e início dos anos setenta (a história da ciência da computação se repete frequentemente): podem ser compiladas linguagens de alto nível para produzir código tão eficiente quanto o código da máquina, digamos, código de montagem, produzido manualmente por um programador. Todo mundo sabe que um programador é muito mais esperto do que qualquer programa e pode ter uma otimização muito inteligente (pensando na maior parte do que agora é chamado de otimização do olho mágico). É claro que isso é ironia da minha parte.
Havia até um conceito de expansão de código: a proporção entre o tamanho do código produzido por um compilador e o tamanho do código para o mesmo programa produzido por um bom programador (como se houvesse muitos deles :-). Obviamente, a idéia era que essa proporção fosse sempre maior que 1. As línguas da época eram Cobol e Fortran 4, ou Algol 60 para os intelectuais. Eu acredito que Lisp não foi considerado.
Bem, havia alguns rumores de que alguém havia produzido um compilador que às vezes podia obter uma taxa de expansão de 1 ... até que simplesmente se tornou a regra que o código compilado era muito melhor do que o código escrito à mão (e mais confiável também). As pessoas estavam preocupadas com o tamanho do código naquela época (pequenas memórias), mas o mesmo vale para velocidade ou consumo de energia. Eu não vou entrar nas razões.
Recursos estranhos, recursos dinâmicos de um idioma não importam. O que importa é como eles são usados, se são usados. O desempenho, em qualquer unidade (tamanho do código, velocidade, energia, ...) geralmente depende de partes muito pequenas dos programas. Portanto, há uma boa chance de as instalações que dão poder expressivo não atrapalharem realmente. Com as boas práticas de programação, as instalações avançadas são usadas apenas de maneira disciplinada, para imaginar novas estruturas (essa foi a lição cega).
O fato de um idioma não ter tipagem estática nunca significou que os programas escritos nesse idioma não sejam digitados estaticamente. Por outro lado, pode ser que o sistema de tipos usado por um programa ainda não esteja suficientemente formalizado para que um verificador de tipos exista agora.
Houve, na discussão, várias referências à análise de pior caso ("problema de parada", análise PERL). Mas a análise do pior caso é principalmente irrelevante. O que importa é o que acontece na maioria dos casos ou em casos úteis ... por mais definidos, compreendidos ou experientes. Aí vem outra história, diretamente relacionada à otimização do programa. Isso aconteceu há muito tempo em uma grande universidade do Texas, entre um estudante de doutorado e seu orientador (que mais tarde foi eleito em uma das academias nacionais). Pelo que me lembro, o aluno insistiu em estudar um problema de análise / otimização que o orientador demonstrou ser intratável. Logo eles não estavam mais falando. Mas o aluno estava certo: o problema era tratável o suficiente na maioria dos casos práticos, de modo que a dissertação que ele produziu se tornou um trabalho de referência.
E para comentar ainda mais a afirmação de que
Perl parsing is not computable
, independentemente do significado dessa frase, existe um problema semelhante com o ML, que é uma linguagem notavelmente bem formalizada.Type checking complexity in ML is a double exponential in the lenght of the program.
Esse é um resultado muito preciso e formal na pior das hipóteses ... o que não importa. No entanto, os usuários de ML ainda estão esperando por um programa prático que exploda o verificador de tipos.Em muitos casos, como era antes, o tempo e a competência humana são mais escassos que o poder computacional.
O verdadeiro problema do futuro será evoluir nossas linguagens para integrar novos conhecimentos, novas formas de programação, sem precisar reescrever todo o software legado que ainda é usado.
Se você olhar para a matemática, é um corpo muito grande de conhecimentos. As linguagens usadas para expressá-lo, notações e conceitos evoluíram ao longo dos séculos. É fácil escrever teoremas antigos com os novos conceitos. Nós adaptamos as principais provas, mas não nos preocupamos com muitos resultados.
Porém, no caso da programação, talvez seja necessário reescrever todas as provas do zero (programas são provas). Pode ser que o que realmente precisamos seja de linguagens de programação evolutivas e de muito alto nível. Os designers do otimizador terão prazer em seguir.
fonte
Algumas notas:
Nem todos os idiomas de alto nível são dinâmicos. Haskell é de nível muito alto, mas é totalmente digitado estaticamente. Mesmo linguagens de programação de sistemas como Rust, Nim e D podem expressar abstrações de alto nível de maneira sucinta e eficiente. De fato, eles podem ser tão concisos quanto as linguagens dinâmicas.
Existem compiladores antecipadamente altamente otimizados para linguagens dinâmicas. As boas implementações de Lisp atingem metade da velocidade do equivalente C.
A compilação JIT pode ser uma grande vitória aqui. O Cloud Application Firewall do CloudFlare gera código Lua que é executado pelo LuaJIT. O LuaJIT otimiza bastante os caminhos de execução realmente usados (normalmente, os caminhos sem ataque), com o resultado de que o código é executado muito mais rápido que o código produzido por um compilador estático na carga de trabalho real. Ao contrário de um compilador estático com otimização guiada por perfil, o LuaJIT se adapta às mudanças nos caminhos de execução no tempo de execução.
A desoptimização também é crucial. Em vez de o código compilado por JIT precisar verificar se uma classe está sendo monkeypatched, o ato de monkeypatching aciona um gancho no sistema de tempo de execução que descarta o código da máquina que dependia da definição antiga.
fonte