Quais são as vantagens e limitações das linguagens de tipos dinâmicas em comparação às linguagens de tipos estáticas?
Veja também : o que há com o amor pelas linguagens dinâmicas (uma discussão muito mais argumentativa ...)
Quais são as vantagens e limitações das linguagens de tipos dinâmicas em comparação às linguagens de tipos estáticas?
Veja também : o que há com o amor pelas linguagens dinâmicas (uma discussão muito mais argumentativa ...)
Respostas:
A capacidade do intérprete de deduzir conversões de tipo e tipo torna o tempo de desenvolvimento mais rápido, mas também pode provocar falhas de tempo de execução que você simplesmente não consegue obter em uma linguagem de tipo estaticamente onde é capturada em tempo de compilação. Mas qual é o melhor (ou mesmo se isso sempre é verdade) é muito discutido na comunidade hoje em dia (e há muito tempo).
Uma boa idéia do problema é de Static Typing, sempre que possível, digitação dinâmica quando necessário: o fim da guerra fria entre linguagens de programação por Erik Meijer e Peter Drayton na Microsoft:
Os defensores da tipagem estática argumentam que as vantagens da tipagem estática incluem detecção anterior de erros de programação (por exemplo, impedindo a adição de um número inteiro a um booleano), melhor documentação na forma de assinaturas de tipo (por exemplo, incorporação de número e tipos de argumentos na resolução de nomes), mais oportunidades para otimizações do compilador (por exemplo, substituição de chamadas virtuais por chamadas diretas quando o tipo exato de receptor é conhecido estaticamente), maior eficiência de tempo de execução (por exemplo, nem todos os valores precisam ter um tipo dinâmico) e uma melhor experiência do desenvolvedor em tempo de design (por exemplo, conhecimento o tipo de receptor, o IDE pode apresentar um menu suspenso de todos os membros aplicáveis). Os fanáticos por digitação estática tentam nos fazer acreditar que “programas bem digitados não podem dar errado”. Embora isso certamente pareça impressionante, é uma afirmação bastante vazia. A verificação de tipo estático é uma abstração em tempo de compilação do comportamento em tempo de execução do seu programa e, portanto, é necessariamente apenas parcialmente parcial e incompleta. Isso significa que os programas ainda podem dar errado devido a propriedades que não são rastreadas pelo verificador de tipos e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. A verificação de tipo estático é uma abstração em tempo de compilação do comportamento em tempo de execução do seu programa e, portanto, é necessariamente apenas parcialmente parcial e incompleta. Isso significa que os programas ainda podem dar errado devido a propriedades que não são rastreadas pelo verificador de tipos e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. A verificação de tipo estático é uma abstração em tempo de compilação do comportamento em tempo de execução do seu programa e, portanto, é necessariamente apenas parcialmente parcial e incompleta. Isso significa que os programas ainda podem dar errado devido a propriedades que não são rastreadas pelo verificador de tipos e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. e, portanto, é necessariamente apenas parcialmente som e incompleto. Isso significa que os programas ainda podem dar errado devido a propriedades que não são rastreadas pelo verificador de tipos e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. e, portanto, é necessariamente apenas parcialmente som e incompleto. Isso significa que os programas ainda podem dar errado devido a propriedades que não são rastreadas pelo verificador de tipos e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha. e que existem programas que, embora não possam dar errado, não podem ser verificados. O impulso de tornar a digitação estática menos parcial e mais completa faz com que os sistemas de tipos se tornem excessivamente complicados e exóticos, como testemunhado por conceitos como "tipos fantasmas" [11] e "tipos bambas" [10]. É como tentar correr uma maratona com uma bola e uma corrente amarradas à sua perna e gritar triunfantemente que você quase conseguiu, mesmo que tenha saído após a primeira milha.
Os defensores das linguagens de tipo dinâmico argumentam que a digitação estática é muito rígida e que a suavidade das linguagens dinamicamente as torna ideais para protótipos de sistemas com requisitos diferentes ou desconhecidos ou que interagem com outros sistemas que mudam imprevisivelmente (integração de dados e aplicativos). Obviamente, linguagens dinamicamente tipadas são indispensáveis para lidar com comportamentos verdadeiramente dinâmicos de programas, como interceptação de métodos, carregamento dinâmico, código móvel, reflexão em tempo de execução, etc. Na mãe de todos os trabalhos sobre scripts [16], John Ousterhout argumenta que sistemas estaticamente tipados as linguagens de programação tornam o código menos reutilizável, mais detalhado, não mais seguro e menos expressivo do que as linguagens de script de tipo dinâmico. Esse argumento é repetido literalmente por muitos defensores de linguagens de script de tipo dinâmico. Argumentamos que isso é uma falácia e se enquadra na mesma categoria que argumentar que a essência da programação declarativa está eliminando a atribuição. Ou, como John Hughes diz [8], é uma impossibilidade lógica de tornar uma linguagem mais poderosa, omitindo recursos. Defender o fato de que atrasar toda verificação de tipo para o tempo de execução é uma coisa boa, está jogando táticas de avestruz com o fato de que os erros devem ser capturados o mais cedo possível no processo de desenvolvimento. é uma impossibilidade lógica tornar uma linguagem mais poderosa, omitindo recursos. Defender o fato de que atrasar toda verificação de tipo para o tempo de execução é uma coisa boa, está jogando táticas de avestruz com o fato de que os erros devem ser capturados o mais cedo possível no processo de desenvolvimento. é uma impossibilidade lógica tornar uma linguagem mais poderosa, omitindo recursos. Defender o fato de que atrasar toda verificação de tipo para o tempo de execução é uma coisa boa, está jogando táticas de avestruz com o fato de que os erros devem ser capturados o mais cedo possível no processo de desenvolvimento.
Os sistemas do tipo estático procuram eliminar certos erros estaticamente, inspecionando o programa sem executá-lo e tentando provar a integridade em certos aspectos. Alguns sistemas de tipos são capazes de detectar mais erros do que outros. Por exemplo, o C # pode eliminar exceções de ponteiro nulo quando usado corretamente, enquanto o Java não tem esse poder. O Twelf possui um sistema de tipos que na verdade garante que as provas serão encerradas , "resolvendo" o problema da interrupção .
No entanto, nenhum sistema de tipos é perfeito. Para eliminar uma classe específica de erros, eles também devem rejeitar certos programas perfeitamente válidos que violam as regras. É por isso que o Twelf não resolve realmente o problema da parada, apenas evita-o lançando um grande número de provas perfeitamente válidas que terminam de maneiras estranhas. Da mesma forma, o sistema de tipos do Java rejeita a PersistentVector
implementação do Clojure devido ao uso de matrizes heterogêneas. Funciona em tempo de execução, mas o sistema de tipos não pode verificá-lo.
Por esse motivo, a maioria dos sistemas de tipos fornece "escapes", maneiras de substituir o verificador estático. Para a maioria dos idiomas, eles assumem a forma de transmissão, embora alguns (como C # e Haskell) possuam modos inteiros marcados como "inseguros".
Subjetivamente, eu gosto de digitar estática. Implementado corretamente (dica: não Java), um sistema de tipo estático pode ser uma grande ajuda para eliminar erros antes que eles travem o sistema de produção. Linguagens de tipo dinâmico tendem a exigir mais testes de unidade, o que é tedioso na melhor das hipóteses. Além disso, linguagens de tipo estaticamente podem ter certos recursos que são impossíveis ou inseguros em sistemas de tipos dinâmicos ( conversões implícitas vêm à mente). É tudo uma questão de requisitos e gosto subjetivo. Eu não construiria mais o próximo Eclipse no Ruby do que tentaria escrever um script de backup no Assembly ou corrigir um kernel usando Java.
Ah, e as pessoas que dizem que " digitar x é 10 vezes mais produtivo que digitar y " estão simplesmente soprando fumaça. Tipagem dinâmica pode "sentir" mais rápido, em muitos casos, mas perde terreno uma vez que você realmente tentar fazer a sua inscrição fantasia prazo . Da mesma forma, a digitação estática pode parecer a rede de segurança perfeita, mas uma olhada em algumas das definições de tipo genérico mais complicadas em Java faz com que a maioria dos desenvolvedores corra atrás dos olhos. Mesmo com sistemas de tipos e produtividade, não há bala de prata.
Nota final: não se preocupe com o desempenho ao comparar a estática com a digitação dinâmica. JITs modernos como V8 e TraceMonkey estão chegando perigosamente perto do desempenho da linguagem estática. Além disso, o fato de o Java realmente ser compilado em uma linguagem intermediária inerentemente dinâmica deve ser uma dica de que, na maioria dos casos, a digitação dinâmica não é a grande causa de desempenho que algumas pessoas pensam ser.
dadd
porque ele sabe com antecedência que os operandos são double
s.
Bem, ambos são muito, muito, muito, muito mal compreendidos e também duas coisas completamente diferentes. que não são mutuamente exclusivos .
Tipos estáticos são uma restrição da gramática do idioma. Pode-se dizer que os idiomas digitados estaticamente não são estritamente livres de contexto. A verdade simples é que torna-se inconveniente expressar uma linguagem de maneira sadia nas gramáticas livres de contexto que não tratam todos os seus dados simplesmente como vetores de bits. Os sistemas de tipo estático fazem parte da gramática da linguagem, se houver, eles simplesmente a restringem mais do que uma gramática livre de contexto poderia, assim, as verificações gramaticais ocorrem em duas passagens sobre a fonte. Os tipos estáticos correspondem à noção matemática da teoria dos tipos; a teoria dos tipos na matemática simplesmente restringe a legalidade de algumas expressões. Tipo, eu não posso dizer 3 + [4,7]
em matemática, isso é por causa da teoria do tipo.
Os tipos estáticos não são, portanto, uma maneira de "evitar erros" de uma perspectiva teórica, são uma limitação da gramática. De fato, desde que +, 3 e intervalos tenham as definições teóricas de conjunto usuais, se removermos o sistema de tipos, o 3 + [4,7]
resultado será um conjunto bem definido. 'erros de tipo de tempo de execução' teoricamente não existem, o uso prático do sistema de tipos é impedir operações que, para seres humanos , não fazem sentido. Operações ainda são apenas a mudança e manipulação de bits, é claro.
O problema é que um sistema de tipos não pode decidir se essas operações ocorrerão ou não, se seria permitido executar. Por exemplo, particione exatamente o conjunto de todos os programas possíveis naqueles que terão um 'erro de tipo' e naqueles que não o são. Ele pode fazer apenas duas coisas:
1: provar que erros de tipo ocorrerão em um programa
2: provar que não ocorrerão em um programa
Pode parecer que eu estou me contradizendo. Mas o que um verificador de tipos C ou Java faz é rejeitar um programa como 'não-gramatical' ou como 'erro de tipo' se não tiver êxito em 2. Não pode provar que eles não ocorrerão, isso não significa que eles não vão ocorrer, apenas significa que não pode provar isso. Pode muito bem ser que um programa que não terá um erro de tipo seja rejeitado simplesmente porque não pode ser provado pelo compilador. Um exemplo simples sendoif(1) a = 3; else a = "string";
, certamente, como sempre é verdade, o ramo else nunca será executado no programa e nenhum erro de tipo deverá ocorrer. Mas não pode provar esses casos de maneira geral, por isso é rejeitado. Essa é a principal fraqueza de muitas linguagens estaticamente tipificadas. Ao proteger você contra si mesmo, você também está necessariamente protegido nos casos em que não precisa.
Mas, ao contrário do que se pensa popular, também existem linguagens de tipo estatístico que funcionam pelo princípio 1. Eles simplesmente rejeitam todos os programas dos quais podem provar que causará um erro de tipo e passam todos os programas dos quais não podem. Portanto, é possível que eles permitam programas com erros de tipo, um bom exemplo sendo o Typed Racket, é híbrido entre a digitação dinâmica e a estática. E alguns argumentam que você obtém o melhor dos dois mundos neste sistema.
Outra vantagem da tipagem estática é que os tipos são conhecidos em tempo de compilação e, portanto, o compilador pode usar isso. Se em Java representamos "string" + "string"
ou 3 + 3
, ambos os +
tokens no texto no final representam uma operação e dado completamente diferentes, o compilador sabe qual escolher apenas os tipos.
Agora, vou fazer uma declaração muito controversa aqui, mas tenha paciência comigo: 'datilografia dinâmica' não existe .
Parece muito controverso, mas é verdade, as linguagens dinamicamente tipadas são de uma perspectiva teórica não tipificadas . Eles são apenas idiomas de tipo estaticamente, com apenas um tipo. Ou, simplesmente, são linguagens que são de fato gramaticalmente geradas por uma gramática livre de contexto na prática.
Por que eles não têm tipos? Como todas as operações são definidas e permitidas em todos os operadores, o que é exatamente um 'erro de tipo de tempo de execução'? É de um exemplo teórico puramente um efeito colateral . Se fazer o print("string")
que imprime uma string é uma operação, o mesmo ocorre com length(3)
o primeiro efeito gravado string
na saída padrão, o último simplesmente error: function 'length' expects array as argument.
, é isso. De uma perspectiva teórica, não existe uma linguagem tipicamente dinâmica. Eles não são tipados
Tudo bem, a vantagem óbvia da linguagem "tipada dinamicamente" é o poder expressivo, um sistema de tipos nada mais é do que uma limitação do poder expressivo. E, em geral, linguagens com um sistema de tipos realmente teriam um resultado definido para todas as operações que não são permitidas se o sistema de tipos fosse apenas ignorado; os resultados simplesmente não teriam sentido para os seres humanos. Muitos idiomas perdem sua integridade de Turing após aplicar um sistema de tipos.
A desvantagem óbvia é o fato de que podem ocorrer operações que produziriam resultados sem sentido para os seres humanos. Para se proteger contra isso, as linguagens dinamicamente tipicamente redefinem essas operações, em vez de produzir esse resultado sem sentido, elas o redefinem para ter o efeito colateral de escrever um erro e possivelmente interromper o programa por completo. Isso não é um "erro", na verdade, a especificação da linguagem geralmente implica isso; esse é o comportamento da linguagem, tanto quanto imprimir uma string de uma perspectiva teórica. Assim, os sistemas de tipos forçam o programador a raciocinar sobre o fluxo do código para garantir que isso não aconteça. Ou, na verdade, a razão para que ele fazO acontecer também pode ser útil em alguns pontos da depuração, mostrando que não é um 'erro', mas uma propriedade bem definida do idioma. De fato, o único remanescente de 'digitação dinâmica' que a maioria dos idiomas possui está protegendo contra uma divisão por zero. É isso que é a digitação dinâmica, não há tipos, não há mais tipos do que zero é um tipo diferente de todos os outros números. O que as pessoas chamam de 'tipo' é apenas outra propriedade de um dado, como o comprimento de uma matriz ou o primeiro caractere de uma sequência. E muitas linguagens de tipo dinâmico também permitem que você escreva coisas assim "error: the first character of this string should be a 'z'"
.
Outra coisa é que as linguagens digitadas dinamicamente têm o tipo disponível em tempo de execução e geralmente podem verificá-lo, lidar com ele e decidir a partir dele. Obviamente, em teoria, não é diferente de acessar o primeiro caractere de uma matriz e ver o que é. De fato, você pode criar seu próprio C dinâmico, apenas use apenas um tipo, como long long int, e use os primeiros 8 bits para armazenar seu 'tipo' e escrever funções de acordo, que o verificam e executam adição de número flutuante ou inteiro. Você tem um idioma digitado estaticamente com um tipo ou um idioma dinâmico.
Na prática, tudo isso mostra que linguagens estaticamente tipificadas são geralmente usadas no contexto de criação de software comercial, enquanto linguagens tipicamente dinâmicas tendem a ser usadas no contexto de solução de alguns problemas e automação de algumas tarefas. Escrever código em linguagens estáticas simplesmente leva muito tempo e é complicado porque você não pode fazer as coisas que sabe que vão dar certo, mas o sistema de tipos ainda protege você contra erros que você não comete. Muitos codificadores nem percebem que fazem isso porque está em seu sistema, mas quando você codifica em linguagens estáticas, geralmente trabalha com o fato de que o sistema de tipos não permite que você faça coisas que não podem dar errado, porque Não posso provar que não vai dar errado.
Como observei, "tipicamente estaticamente" em geral significa o caso 2, culpado até que se prove inocente. Mas algumas linguagens, que não derivam seu sistema de tipos da teoria de tipos, usam a regra 1: inocente até que se prove o contrário, que pode ser o híbrido ideal. Então, talvez o Typed Racket seja para você.
Além disso, para um exemplo mais absurdo e extremo, atualmente estou implementando uma linguagem em que 'tipos' são realmente o primeiro caractere de uma matriz, são dados, dados do 'tipo', 'tipo', que é ele próprio um tipo e dado, o único dado que tem a si próprio como um tipo. Os tipos não são finitos ou delimitados estaticamente, mas novos tipos podem ser gerados com base nas informações de tempo de execução.
Talvez o maior "benefício" da digitação dinâmica seja a curva de aprendizado mais superficial. Não existe um sistema de tipos para aprender e nenhuma sintaxe não trivial para maiúsculas e minúsculas, como restrições de tipo. Isso torna a digitação dinâmica acessível a muito mais pessoas e possível para muitas pessoas para as quais sistemas sofisticados de tipo estático estão fora de alcance. Conseqüentemente, a digitação dinâmica captou os contextos da educação (por exemplo, Scheme / Python no MIT) e as linguagens específicas de domínio para não programadores (por exemplo, o Mathematica ). As linguagens dinâmicas também se destacaram em nichos em que eles têm pouca ou nenhuma concorrência (por exemplo, Javascript).
As linguagens de tipo dinâmico mais concisas (por exemplo, Perl, APL, J, K, Mathematica ) são específicas do domínio e podem ser significativamente mais concisas do que as linguagens de tipo estatístico de uso geral mais concisas (por exemplo, OCaml ) nos nichos para os quais foram projetadas. .
As principais desvantagens da digitação dinâmica são:
Erros de tipo em tempo de execução.
Pode ser muito difícil ou até praticamente impossível atingir o mesmo nível de correção e requer muito mais testes.
Nenhuma documentação verificada pelo compilador.
Baixo desempenho (geralmente em tempo de execução, mas às vezes em tempo de compilação, por exemplo, esquema de Stalin) e desempenho imprevisível devido à dependência de otimizações sofisticadas.
Pessoalmente, eu cresci em linguagens dinâmicas, mas não as tocaria como profissional, a menos que não houvesse outras opções viáveis.
Artigo : Digitação de Artima : artigo forte vs. fraco, estático vs. dinâmico :
A digitação forte evita operações de mistura entre tipos incompatíveis. Para misturar tipos, você deve usar uma conversão explícita
digitação fraca significa que você pode misturar tipos sem uma conversão explícita
No artigo de Pascal Costanza, Dynamic vs Static Typing - Uma análise baseada em padrões (PDF), ele afirma que, em alguns casos, a digitação estática é mais suscetível a erros do que a digitação dinâmica. Alguns idiomas de tipo estaticamente forçam você a emular manualmente a digitação dinâmica para executar "The Right Thing". É discutido no Lambda the Ultimate .
Depende do contexto. Existem muitos benefícios que são apropriados para o sistema de digitação dinâmica e para a digitação forte. Sou de opinião que o fluxo da linguagem de tipos dinâmicos é mais rápido. As linguagens dinâmicas não são restritas aos atributos de classe e ao pensamento do compilador sobre o que está acontecendo no código. Você tem um pouco de liberdade. Além disso, a linguagem dinâmica geralmente é mais expressiva e resulta em menos código, o que é bom. Apesar disso, é mais suscetível a erros, o que também é questionável e depende mais da cobertura do teste de unidade. É um protótipo fácil com dinâmica, mas a manutenção pode se tornar um pesadelo.
O principal ganho em relação ao sistema estático digitado é o suporte a IDE e, certamente, o analisador estático de código. Você se torna mais confiante em relação ao código após cada alteração. A manutenção é tranqüila com essas ferramentas.
Existem muitas coisas diferentes sobre linguagens estáticas e dinâmicas. Para mim, a principal diferença é que nas linguagens dinâmicas as variáveis não têm tipos fixos; em vez disso, os tipos estão vinculados a valores. Por esse motivo, o código exato que é executado é indeterminado até o tempo de execução.
Nas implementações iniciais ou ingênuas, esse é um enorme prejuízo para o desempenho, mas os JITs modernos ficam tentadoramente próximos do melhor que você pode obter com a otimização de compiladores estáticos. (em alguns casos adicionais, ainda melhor que isso).
É tudo sobre a ferramenta certa para o trabalho. Nem é melhor 100% do tempo. Ambos os sistemas foram criados pelo homem e têm falhas. Desculpe, mas nós somos péssimos e fazemos coisas perfeitas.
Eu gosto da digitação dinâmica porque fica fora do meu caminho, mas sim erros de tempo de execução podem surgir que eu não planejava. Onde a digitação estática pode corrigir os erros mencionados anteriormente, mas deixa um programador iniciante (em linguagens digitadas) louco tentando converter entre um caractere e uma string constantes.
Digitação estática: idiomas como Java e Scala são de estática.
As variáveis precisam ser definidas e inicializadas antes de serem usadas em um código.
para ex. int x; x = 10;
System.out.println (x);
Digitação dinâmica: Perl é uma linguagem de digitação dinâmica.
Variáveis não precisam ser inicializadas antes de serem usadas no código.
y = 10; use essa variável na parte posterior do código