Pergunta

Pergunta simples pessoal:Faço muita programação (profissional e pessoalmente) em linguagens compiladas como C++/Java e em linguagens interpretadas como Python/Javascript.Pessoalmente, acho que meu código é quase sempre mais robusto quando programo em linguagens de tipo estaticamente.No entanto, quase todas as linguagens interpretadas que encontro usam tipagem dinâmica (PHP, Perl, Python, etc.).Eu sei por que as linguagens compiladas usam digitação estática (na maioria das vezes), mas não consigo entender a aversão à digitação estática no design de linguagem interpretada.

Por que a desconexão acentuada?Faz parte da natureza das linguagens interpretadas?OP?

Foi útil?

Solução

Pergunta interessante. Btw, eu sou o autor/mantenedor de phc (Compilador para PHP) e estou fazendo meu doutorado em compiladores para idiomas dinâmicos, então espero poder oferecer algumas idéias.

Eu acho que há uma suposição equivocada aqui. Os autores de PHP, Perl, Python, Ruby, Lua, etc. não projetaram "idiomas interpretados", eles projetaram idiomas dinâmicos e os implementaram usando intérpretes. Eles fizeram isso porque os intérpretes são muito mais fáceis de escrever do que os compiladores.

A primeira implementação de Java foi interpretada e é um idioma estaticamente digitado. Os intérpretes existem para as línguas estáticas: Haskell e Ocaml têm intérpretes, e costumava haver um intérprete popular para C, mas isso foi há muito tempo. Eles são populares porque permitem um Repl, o que pode facilitar o desenvolvimento.

Dito isto, há uma aversão à digitação estática na comunidade de linguagem dinâmica, como seria de esperar. Eles acreditam que os sistemas de tipo estático fornecidos por C, C ++ e Java são detalhados e não valem o esforço. Acho que concordo com isso até certo ponto. A programação no Python é muito mais divertida que o C ++.

Para abordar os pontos de outros:

  • Dlamblin diz: "Eu nunca senti fortemente que havia algo de especial na compilação versus interpretação que sugeriu dinâmica sobre a digitação estática". Bem, você está muito errado lá. A compilação de linguagens dinâmicas é muito difícil. Existe principalmente o eval Declaração a considerar, que é usada extensivamente em JavaScript e Ruby. A PHC compila PHP antes do tempo, mas ainda precisamos de um intérprete de tempo de execução para lidar evals. eval também não pode ser analisado estaticamente em um compilador de otimização, embora exista um técnica legal Se você não precisa de solidez.

  • À resposta de Damblin a Andrew Hare: Você pode, é claro, realizar análises estáticas em um intérprete e encontrar erros antes da tempo de execução, que é exatamente o que Haskell's ghci faz. Espero que o estilo de intérprete usado em idiomas funcionais exija isso. Dlamblin tem o direito de dizer que a análise não faz parte da interpretação.

  • Resposta de Andrew Hare É baseado na suposição errada dos interrogadores e, da mesma forma, tem as coisas da maneira errada. No entanto, ele levanta uma questão interessante: "Quão difícil é a análise estática das línguas dinâmicas?". Muito, muito difícil. Basicamente, você obterá um doutorado por descrever como funciona, que é exatamente o que estou fazendo. Veja também o ponto anterior.

  • A resposta mais correta até agora é a de Ivo Wetzel. No entanto, os pontos que ele descreve podem ser tratados em tempo de execução em um compilador, e muitos compiladores existem para o LISP e o esquema que possuem esse tipo de ligação dinâmica. Mas, sim, é complicado.

Outras dicas

Linguagens interpretadas usam tipagem dinâmica porque não há etapa de compilação para fazer a análise estática.Linguagens compiladas fazem análise estática em tempo de compilação o que significa que quaisquer erros de tipo são relatados ao desenvolvedor à medida que funcionam.

É mais fácil entender se você considerar que uma linguagem de tipo estaticamente possui um compilador que impõe regras de tipo fora do contexto de execução.As linguagens interpretadas nunca são analisadas estaticamente, portanto as regras de tipo devem ser aplicadas pelo intérprete dentro do contexto de execução.

Eu acho que é por causa da natureza dos idiomas interpretados, eles querem ser dinâmicos, para que você possa mudar as coisas em tempo de execução. Devido a isso, um compilador nunca sabe exatamente qual é o estado do programa depois que a próxima linha de código foi excluída.

Imagine o seguinte cenário (em Python):

import random
foo = 1

def doSomeStuffWithFoo():
    global foo
    foo = random.randint(0, 1)

def asign():
    global foo
    if foo == 1:
        return 20
    else:
        return "Test"


def toBeStaticallyAnalyzed():
    myValue = asign()

    # A "Compiler" may throw an error here because foo == 0, but at runtime foo maybe 1, so the compiler would be wrong with its assumption
    myValue += 20


doSomeStuffWithFoo() # Foo could be 1 or 0 now... or 4 ;)
toBeStaticallyAnalyzed()

Como você pode ver, um compilador não faria sentido nessa situação. Aumente, isso poderia avisá -lo sobre a possibilidade de que "MyValue" talvez outra coisa que não seja um número. Mas então, no JavaScript, que falharia porque, se "myValue" for uma string, 20 seriam imploradamente convertidos em uma string também, portanto, nenhum erro ocorreria. Portanto, você pode receber milhares de avisos inúteis em todo o lugar, e eu não acho que esse seja o pretendimento de um compilador.

A flexibilidade sempre vem com um preço, você precisa analisar mais profundamente seu programa ou programá -lo com mais cuidado, em outras palavras, você é o compilador em situações como as acima.

Então, sua solução como compilador? - Corrija com uma "tentativa: exceto" :)

Compiladores + tipos estáticos = código de máquina eficiente
Compiladores + tipos dinâmicos = código de máquina ineficiente

Considere o seguinte pseudocódigo:

function foo(a, b) {
    return a+b
}

Uma linguagem estática poderá saber (por declaração ou inferência) que A e B são inteiros e se compilarão até

%reg = addi a,b

Ou algo semelhante, de qualquer maneira.

Um compilador para uma linguagem dinâmica teria que emitir código para
1. Verifique se eles são tipos de A e B
2. Lidar com cada caso ou combinação de casos

%reg1 = typeof a
beq %reg1, int, a_int_case
beq %reg1, float, a_float_case
beq %reg1, string, a_string_case

label a_int_case
%reg1 = typeof b
beq %reg1, int, a_int_b_int_case
beq %reg1, float, a_int_b_float_case
beq %reg1, string, a_int_b_string_case

label a_int_b_int_case
%out = addi a,b
goto done

label a_int_b_float_case
%tmp = mkfloat a
%out = addf %tmp,b
goto done

... Etc. I can't finish

Embora você possa gerar código de máquina mais inteligente do que isso, você não poderá ajudar a gerar muito código - o que torna a compilação não uma grande vitória para um idioma dinâmico.

Como os intérpretes são muito mais fáceis de escrever e a compilação não é muito bem, por que não escrever um intérprete?

(Os compiladores just-in-time realmente têm informações de tipo e podem compilar até a declaração única. Na verdade, eles têm mais informações do que os sistemas de tipo estático e podem teoricamente se sair ainda melhor. Todo o assembler é simulado; qualquer semelhança com código real que Poderia correr em uma máquina real é puramente coincidente.)

Talvez seja porque uma das minhas principais línguas interpretadas é Perl e uma das minhas línguas compiladas é o Objective-C, mas nunca senti fortemente que havia algo especial na compilação versus interpretação que sugeriu dinâmica sobre a digitação estática.

Eu acho que está claro que ambos os lados estão olhando para o outro e pensando: "Há algumas vantagens nisso". É mais fácil em vários aplicativos obter uma flexibilidade do tipo dinâmico, enquanto pode ser mais fácil manter algo que seja estaticamente digitado e aplicado.

Eu discordo com Explicação de Andrew Hare no entanto. Embora uma linguagem puramente interpretada teria que adicionar uma etapa de pré-processamento e, portanto, não ser puramente interpretada para avisar o programador antes da execução de erros de digitação estática, não impede o lançamento de um erro de tipo no tempo de execução, pois ocorre. Portanto, a falta de compilação não significa que nenhuma verificação estática pode ocorrer. Mas como receber um erro de tipo em tempo de execução não é tão útil quanto obter um na compilação ou durante uma verificação de pré-voo, posso ver como a "vantagem" da digitação estática nessa situação pode parecer mais um incômodo, e assim é expulso em favor da dinâmica dinâmica de vantagens.

Se você soube desde o início que prefere manter seus tipos estáticos, porque pessoalmente escreve um código mais mantido mais mantido e como resultado, e estava projetando seu idioma interpretado, nada deve impedir que você projete o idioma como um tipado estaticamente.

Para citar o Artigo Wiki de idiomas interpretado "Teoricamente, qualquer idioma pode ser compilado ou interpretado; portanto, essa designação é aplicada exclusivamente devido à prática de implementação comum e não a alguma propriedade subjacente de um idioma".
Há um decente Artigo do Wiki apenas na digitação.

Linguagens interpretadas de tipo dinâmico oferecem mais liberdade na maneira como você programa.Isso permite que a metaprogramação seja viável.Ele permite que variáveis ​​sejam criadas em tempo de execução.Permite que hashes anônimos e arrays anônimos sejam criados a qualquer momento durante o tempo de execução, sem nunca declarar nada previamente.Ele permite que informações indeterminadas sejam inseridas em um hash sem nunca declarar todas as chaves antecipadamente.Você pode criar sub-rotinas a partir de entradas aleatórias indeterminadas.Você também pode alimentar um código de programa que pode ser executado dinamicamente.As linguagens interpretadas libertam as cadeias que limitam a programação em geral.Você está limitado ao que digita no arquivo de origem com linguagens de tipo estaticamente.Você pode fazer mais com menos em uma linguagem de tipo dinâmico.

A maioria dos robôs fabricados hoje lidam mais com linguagens interpretadas porque as informações precisam ser determinadas em tempo de execução e novas variáveis ​​precisam ser criadas para armazenar essas informações em tempo de execução.O aprendizado de máquina é baseado na interpretação da informação.Nós próprios, como humanos, somos intérpretes e é por isso que os robôs estão sendo projetados dessa forma.O futuro realmente é interpretado.É claro que você precisa de linguagens de tipo estaticamente para construir intérpretes, de modo que linguagens de tipo estaticamente nunca desaparecerão, a menos que os intérpretes sejam construídos em código assembly no futuro.Atualmente, a maioria dos intérpretes é construída sobre linguagens de tipo estaticamente.

Linguagens interpretadas se destacam em um ambiente dinâmico.Se você pode interpretar novos códigos/informações em tempo de execução, por que não?Se você é realmente bom em programação dinâmica, então você pode criar código que pode criar variáveis ​​e hashes sem precisar digitar tudo.Você pode reduzir drasticamente a quantidade de linhas se estiver trabalhando com grandes quantidades de dados.Você pode usar um dumper de dados para imprimir todas as suas informações porque as linguagens interpretadas geralmente rastreiam o tipo de variáveis ​​em tempo de execução, permitindo que isso seja possível.Você não pode fazer isso em barebones c++.A única vez que c++ e c sabem o que está acontecendo é em tempo de compilação.Depois disso, você estará sozinho, a menos que implemente algo sozinho.

Quem quer estar tão preso ao arquivo de origem hoje em dia, especialmente quando você trabalha em ambientes dinâmicos.Tudo o que você faz está limitando seu potencial.Uma vez mergulhado no código interpretado dinamicamente e você voltar para qualquer linguagem de tipo estaticamente, será mais difícil emburrecer seu código porque você ainda está pensando em uma mentalidade ilimitada.Sua mente precisa voltar a ficar limitada novamente ao que está digitado no arquivo de origem.

No que diz respeito aos estilos de programação:O código digitado estaticamente produz resultados estáticos.O código digitado dinamicamente produz resultados dinâmicos ou estáticos.

Se você vai programar algo que nunca muda o comportamento além do que é conhecido, as linguagens de tipo estaticamente são ótimas para isso.Se você está lidando com comportamento dinâmico, então linguagens de tipo dinâmico são mais adequado para esses casos.Tudo depende principalmente da situação.

Cada idioma tem seus altos e baixos.Só preciso escolher e escolher com sabedoria.

Acho que a digitação estática facilita para os compiladores e essa é a principal (se não a única) razão pela qual ela está presente nas linguagens compiladas.

Para linguagens interpretadas, é mais fácil assumir que as variáveis ​​não têm tipo (apenas os valores têm), porque elas são pensadas não como um marcador para os dados que devem caber dentro, mas sim como um rótulo para os dados que flutuam em algum lugar da pilha.

Se o programador quiser, ele sempre pode afirmar que a variável contém um valor de determinado tipo (por exemplo, na atribuição).Não há razão para incorporá-lo na linguagem.É claro que esse não é o mesmo tipo de controle que você tem para linguagens compiladas.

Você provavelmente poderia ter uma linguagem na qual deveria declarar explicitamente o tipo de cada variável, mas se não o fizer, será muito mais fácil fazer coisas interessantes que, com a digitação estática, exigiriam do programador tipos genéricos complexos cuidadosamente elaborados.

Por outro lado.Você conhece alguma linguagem compilada de tipo dinâmico (estaticamente, não JIT)?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top