Eu ouço muito que novas linguagens de programação são digitadas dinamicamente, mas o que realmente significa quando dizemos que uma linguagem é digitada dinamicamente versus estaticamente?
Eu ouço muito que novas linguagens de programação são digitadas dinamicamente, mas o que realmente significa quando dizemos que uma linguagem é digitada dinamicamente versus estaticamente?
Respostas:
Um idioma é digitado estaticamente se o tipo de uma variável for conhecido no momento da compilação. Para algumas linguagens, isso significa que você, como programador, deve especificar que tipo de variável é (por exemplo: Java, C, C ++); outros idiomas oferecem alguma forma de inferência de tipo , a capacidade do sistema de tipos de deduzir o tipo de uma variável (por exemplo: OCaml, Haskell, Scala, Kotlin)
A principal vantagem aqui é que todos os tipos de verificação podem ser feitos pelo compilador e, portanto, muitos bugs triviais são detectados em um estágio muito inicial.
Exemplos: C, C ++, Java, Rust, Go, Scala
Um idioma é digitado dinamicamente se o tipo estiver associado aos valores de tempo de execução e não nomeado variáveis / campos / etc. Isso significa que você como programador pode escrever um pouco mais rápido, porque você não precisa especificar tipos todas as vezes (a menos que esteja usando uma linguagem de tipo estaticamente com inferência de tipo ).
Exemplos: Perl, Ruby, Python, PHP, JavaScript
A maioria das linguagens de script possui esse recurso, pois não há compilador para fazer a verificação estática de tipo, mas você pode encontrar um bug causado pelo interpretador interpretar mal o tipo de uma variável. Felizmente, os scripts tendem a ser pequenos, então os bugs não têm muitos lugares para se esconder.
A maioria dos idiomas digitados dinamicamente permite que você forneça informações de tipo, mas não as exigem. Um idioma que está sendo desenvolvido atualmente, o Rascal , adota uma abordagem híbrida, permitindo a digitação dinâmica nas funções, mas reforçando a digitação estática para a assinatura da função.
Linguagens de programação com tipos estatísticos realizam verificação de tipo (ou seja, o processo de verificação e imposição das restrições de tipos) no tempo de compilação, em vez do tempo de execução .
As linguagens de programação dinamicamente digitadas fazem a verificação de tipo no tempo de execução, em vez do tempo de compilação .
Exemplos de linguagens estaticamente tipadas são: - Java, C, C ++
Exemplos de linguagens dinamicamente tipadas são: - Perl, Ruby, Python, PHP, JavaScript
Aqui está um exemplo contrastando como Python (digitado dinamicamente) e Go (estaticamente) lidam com um erro de tipo:
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
O Python digita a verificação no tempo de execução e, portanto:
silly(2)
Funciona perfeitamente e produz a saída esperada Hi
. O erro é gerado apenas se a linha problemática for atingida:
silly(-1)
Produz
TypeError: unsupported operand type(s) for +: 'int' and 'str'
porque a linha relevante foi realmente executada.
Por outro lado, verifica o tipo em tempo de compilação:
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
O acima não será compilado, com o seguinte erro:
invalid operation: "3" + 5 (mismatched types string and int)
runhaskell
, por exemplo.
Simplificando, desta maneira: em uma linguagem de tipo estaticamente, os tipos de variáveis são estáticos , ou seja, depois de definir uma variável para um tipo, você não pode alterá-la. Isso ocorre porque a digitação está associada à variável e não ao valor a que se refere.
Por exemplo em Java:
String str = "Hello"; //variable str statically typed as string
str = 5; //would throw an error since str is supposed to be a string only
Onde, por outro lado: em um idioma digitado dinamicamente, os tipos de variáveis são dinâmicos , ou seja, depois de definir uma variável para um tipo, você PODE alterá-la. Isso ocorre porque a digitação está associada ao valor que ela assume e não à própria variável.
Por exemplo, em Python:
str = "Hello" # variable str is linked to a string value
str = 5 # now it is linked to an integer value; perfectly OK
Portanto, é melhor pensar em variáveis em linguagens digitadas dinamicamente como apenas indicadores genéricos para valores digitados.
Para resumir, o tipo descreve (ou deveria ter descrito) as variáveis no idioma e não no próprio idioma. Poderia ter sido melhor usado como uma linguagem com variáveis de tipo estatístico versus uma linguagem com variáveis de tipo dinâmico IMHO.
Linguagens tipicamente estáticas geralmente são linguagens compiladas, portanto, os compiladores verificam os tipos (fazem todo o sentido, pois não é permitido alterar os tipos posteriormente no tempo de execução).
Os idiomas digitados dinamicamente são geralmente interpretados, portanto, a verificação de tipo (se houver) acontece no tempo de execução quando são usados. É claro que isso traz algum custo de desempenho e é uma das razões pelas quais as linguagens dinâmicas (por exemplo, python, ruby, php) não são tão boas quanto as digitadas (java, c #, etc.). De outra perspectiva, as linguagens estaticamente tipificadas têm um custo inicial maior: normalmente você escreve mais código, código mais difícil. Mas isso vale mais tarde.
A coisa boa é que ambos os lados estão emprestando recursos do outro lado. As linguagens digitadas estão incorporando recursos mais dinâmicos, por exemplo, bibliotecas genéricas e dinâmicas em c #, e as linguagens dinâmicas incluem mais verificação de tipo, por exemplo, anotações de tipo em python ou variante HACK do PHP, que geralmente não são essenciais para a linguagem e podem ser usadas em exigem.
Quando se trata de seleção de tecnologia, nenhum dos lados tem uma superioridade intrínseca sobre o outro. É apenas uma questão de preferência se você deseja ter mais controle ou flexibilidade. basta escolher a ferramenta certa para o trabalho e verificar o que está disponível em termos opostos antes de considerar uma opção.
http://en.wikipedia.org/wiki/Type_system
Digitação estática
Diz-se que uma linguagem de programação usa digitação estática quando a verificação de tipo é realizada durante o tempo de compilação, em oposição ao tempo de execução. Na digitação estática, os tipos são associados a variáveis e não valores. Linguagens de tipo estático incluem Ada, C, C ++, C #, JADE, Java, Fortran, Haskell, ML, Pascal, Perl (com relação à diferenciação de escalares, matrizes, hashes e sub-rotinas) e Scala. A digitação estática é uma forma limitada de verificação do programa (consulte segurança do tipo): portanto, permite que muitos erros de tipo sejam detectados no início do ciclo de desenvolvimento. Os verificadores de tipo estático avaliam apenas as informações de tipo que podem ser determinadas em tempo de compilação, mas são capazes de verificar se as condições verificadas são válidas para todas as execuções possíveis do programa, o que elimina a necessidade de repetir as verificações de tipo toda vez que o programa é executado. A execução do programa também pode ser mais eficiente (ou seja, mais rápido ou com menos memória), omitindo as verificações de tipo de tempo de execução e permitindo outras otimizações.
Como eles avaliam informações de tipo durante a compilação e, portanto, não possuem informações de tipo disponíveis apenas em tempo de execução, os verificadores de tipo estático são conservadores. Eles rejeitarão alguns programas que podem ser bem comportados em tempo de execução, mas que não podem ser estaticamente determinados para serem bem digitados. Por exemplo, mesmo se uma expressão sempre é avaliada como verdadeira no tempo de execução, um programa que contém o código
if <complex test> then 42 else <type error>
será rejeitado como digitado incorretamente, porque uma análise estática não pode determinar que o ramo else não será utilizado. [1] O comportamento conservador dos verificadores de tipo estático é vantajoso quando avaliado como falso com pouca frequência: Um verificador de tipo estático pode detectar erros de tipo em caminhos de código raramente usados. Sem verificação de tipo estático, mesmo os testes de cobertura de código com 100% de cobertura de código podem não conseguir encontrar esses erros de tipo. Os testes de cobertura de código podem falhar na detecção de tais erros de tipo porque a combinação de todos os locais onde os valores são criados e todos os locais onde um determinado valor é usado deve ser levada em consideração.
As linguagens de tipo estaticamente mais usadas não são formalmente seguras. Eles têm "brechas" na especificação da linguagem de programação, permitindo que os programadores escrevam códigos que contornem a verificação executada por um verificador de tipo estático e, portanto, resolvam uma variedade maior de problemas. Por exemplo, Java e a maioria das linguagens de estilo C têm punção de tipo e Haskell possui recursos como unsafePerformIO: essas operações podem não ser seguras em tempo de execução, pois podem causar comportamento indesejado devido à digitação incorreta de valores quando o programa é executado.
Digitação dinâmica
Diz-se que uma linguagem de programação é digitada dinamicamente, ou apenas 'dinâmica', quando a maioria de sua verificação de tipo é executada em tempo de execução, em vez de em tempo de compilação. Na digitação dinâmica, os tipos são associados a valores e não variáveis. As linguagens digitadas dinamicamente incluem Groovy, JavaScript, Lisp, Lua, Objective-C, Perl (com relação aos tipos definidos pelo usuário, mas não aos tipos internos), PHP, Prolog, Python, Ruby, Smalltalk e Tcl. Comparada à tipagem estática, a tipagem dinâmica pode ser mais flexível (por exemplo, permitindo que os programas gerem tipos e funcionalidades com base em dados de tempo de execução), embora à custa de menos garantias a priori. Isso ocorre porque uma linguagem digitada dinamicamente aceita e tenta executar alguns programas que podem ser considerados inválidos por um verificador de tipo estático.
A digitação dinâmica pode resultar em erros de tipo de tempo de execução - ou seja, em tempo de execução, um valor pode ter um tipo inesperado e uma operação sem sentido para esse tipo é aplicada. Essa operação pode ocorrer muito depois do local em que o erro de programação foi cometido - ou seja, o local onde o tipo errado de dados passou para um local que não deveria ter. Isso dificulta a localização do bug.
Os sistemas de linguagem tipicamente dinamizados, em comparação com seus primos estaticamente tipificados, fazem menos verificações em "tempo de compilação" no código-fonte (mas verificam, por exemplo, se o programa está sintaticamente correto). As verificações em tempo de execução podem ser potencialmente mais sofisticadas, pois podem usar informações dinâmicas e qualquer informação presente durante a compilação. Por outro lado, as verificações de tempo de execução apenas afirmam que as condições são mantidas em uma execução específica do programa e essas verificações são repetidas para cada execução do programa.
O desenvolvimento em linguagens dinamicamente tipificadas é frequentemente suportado por práticas de programação como teste de unidade. O teste é uma prática essencial no desenvolvimento profissional de software e é particularmente importante em linguagens de tipo dinâmico. Na prática, os testes realizados para garantir a operação correta do programa podem detectar uma gama muito maior de erros do que a verificação de tipo estática, mas, inversamente, não podem procurar de maneira tão abrangente os erros que os testes e a verificação de tipo estática são capazes de detectar. O teste pode ser incorporado ao ciclo de criação do software, caso em que pode ser considerado como uma verificação de "tempo de compilação", pois o usuário do programa não precisará executar manualmente esses testes.
Referências
- Pierce, Benjamin (2002). Tipos e linguagens de programação. MIT Pressione. ISBN 0-262-16209-1.
myObject[remoteDataName]
. Então não há como saber qual propriedade ela escolherá ou mesmo se é uma propriedade válida.
Infelizmente, a terminologia "digitada dinamicamente" é enganosa. Todos os idiomas são digitados estaticamente e os tipos são propriedades de expressões (não de valores, como alguns pensam). No entanto, alguns idiomas têm apenas um tipo. Eles são chamados de idiomas uni-tipados. Um exemplo dessa linguagem é o cálculo lambda sem tipo.
No cálculo lambda sem tipo, todos os termos são termos lambda, e a única operação que pode ser executada em um termo é aplicá-lo a outro termo. Portanto, todas as operações sempre resultam em recursão infinita ou em um termo lambda, mas nunca sinalizam um erro.
No entanto, fomos para aumentar o cálculo lambda sem tipo com números de primitivas e operações aritméticas, depois, pode executar operações sem sentido, tais adicionando dois termos lambda juntos: (λx.x) + (λy.y)
. Alguém poderia argumentar que a única coisa sensata a fazer é sinalizar um erro quando isso acontecer, mas para poder fazer isso, cada valor deve ser marcado com um indicador que indica se o termo é um termo lambda ou um número. O operador de adição verificará se realmente os dois argumentos estão marcados como números e, se não estiverem, sinalizam um erro. Observe que essas tags não são tipos, porque tipos são propriedades de programas, não de valores produzidos por esses programas.
Uma linguagem uni-digitada que faz isso é chamada de digitação dinâmica.
Idiomas como JavaScript, Python e Ruby são todos digitados. Novamente, o typeof
operador em JavaScript e a type
função em Python têm nomes enganosos; eles retornam as tags associadas aos operandos, não seus tipos. Da mesma forma, dynamic_cast
em C ++ e instanceof
em Java não faça verificações de tipo.
"Quando o código fonte é traduzido"
"Quando tipos são verificados"
5 + '3'
é um exemplo de erro de tipo em linguagens fortemente tipadas como Go e Python, porque elas não permitem "coerção de tipo" -> a capacidade de um valor alterar o tipo em determinados contextos, como mesclar dois tipos. Idiomas de tipo fraco , como JavaScript, não geram erro de tipo (resulta em '53'
).
As definições de "Estático e compilado" e "Dinâmico e interpretado" são bastante semelhantes ... mas lembre-se de que é "quando os tipos são verificados" vs. "quando o código-fonte é traduzido".
Você receberá os mesmos erros de tipo, independentemente de o idioma ser compilado ou interpretado ! Você precisa separar esses termos conceitualmente.
Dinâmico, Interpretado
def silly(a):
if a > 0:
print 'Hi'
else:
print 5 + '3'
silly(2)
Como o Python é interpretado e digitado dinamicamente, ele apenas converte e verifica o código de verificação de tipo em que está executando. O else
bloco nunca é executado, então5 + '3'
nunca é visto!
E se fosse digitado estaticamente?
Um erro de tipo seria gerado antes mesmo da execução do código. Ele ainda executa a verificação de tipo antes do tempo de execução, mesmo que seja interpretado.
E se fosse compilado?
O else
bloco seria traduzido / analisado antes do tempo de execução, mas como é digitado dinamicamente, não gera erro! Linguagens tipadas dinamicamente não verificam tipos até a execução, e essa linha nunca é executada.
Estático, Compilado
package main
import ("fmt"
)
func silly(a int) {
if (a > 0) {
fmt.Println("Hi")
} else {
fmt.Println("3" + 5)
}
}
func main() {
silly(2)
}
Os tipos são verificados antes da execução (estáticos) e o erro de tipo é capturado imediatamente! Os tipos ainda seriam verificados antes do tempo de execução, se fossem interpretados, tendo o mesmo resultado. Se fosse dinâmico, não lançaria nenhum erro, mesmo que o código fosse analisado durante a compilação.
Uma linguagem compilada terá melhor desempenho em tempo de execução se for digitada estaticamente (vs. dinamicamente); O conhecimento dos tipos permite a otimização do código da máquina.
Linguagens de tipo estático têm melhor desempenho em tempo de execução intrinsecamente devido à não necessidade de verificar tipos dinamicamente durante a execução (verifica antes de executar).
Da mesma forma, os idiomas compilados são mais rápidos no tempo de execução, pois o código já foi traduzido em vez de precisar "interpretar" / traduzir rapidamente.
Observe que os idiomas compilados e estaticamente tipificados terão um atraso antes de serem executados para tradução e verificação de tipo, respectivamente.
A digitação estática captura os erros mais cedo, em vez de encontrá-los durante a execução (especialmente útil para programas longos). É mais "rigoroso", pois não permite erros de tipo em nenhum lugar do programa e geralmente impede que variáveis alterem os tipos, o que se defende ainda mais contra erros não intencionais.
num = 2
num = '3' // ERROR
A digitação dinâmica é mais flexível, o que alguns apreciam. Geralmente, permite que variáveis alterem tipos, o que pode resultar em erros inesperados.
Linguagens de tipo estático : cada variável e expressão já é conhecida no momento da compilação.
( int a;
a pode levar apenas valores de tipo inteiro em tempo de execução)
Exemplos: C, C ++, Java
Idiomas digitados dinamicamente : variáveis podem receber valores diferentes em tempo de execução e seu tipo é definido em tempo de execução.
( var a;
a pode receber qualquer tipo de valor em tempo de execução)
Exemplos: Ruby, Python.
A verificação de tipo de idiomas digitados estaticamente no momento da compilação e o tipo NÃO pode ser alterado. (Não seja engraçado com comentários de conversão de tipo, uma nova variável / referência é criada).
A verificação de tipo de idiomas dinamicamente digitados no tempo de execução e o tipo de uma variável PODEM ser alterados no tempo de execução.
Definições simples e doces, mas que atendem à necessidade: Idiomas digitados estaticamente vinculam o tipo a uma variável para todo o seu escopo (Seg: SCALA) Idiomas digitados dinamicamente vinculam o tipo ao valor real referenciado por uma variável.
Linguagens de tipo estático, como C ++, Java e linguagens de tipo dinâmico, como Python, diferem apenas em termos de execução do tipo da variável. Linguagens tipicamente estáticas têm tipo de dados estático para a variável, aqui o tipo de dados é verificado durante a compilação, portanto a depuração é muito mais simples ... enquanto tipicamente dinamicamente não fazem o mesmo, o tipo de dados é verificado em que execução do programa e, portanto, o a depuração é um pouco difícil.
Além disso, eles têm uma diferença muito pequena e podem estar relacionados a linguagens fortemente tipadas e fracamente tipadas . Uma linguagem fortemente tipada não permite que você use um tipo como outro, por exemplo. C e C ++ ... enquanto linguagens de tipo fraco permitem, por exemplo, o python
Digitado estaticamente
Os tipos são verificados antes do tempo de execução para que erros possam ser detectados anteriormente.
Exemplos = c ++
Digitado dinamicamente
Os tipos são verificados durante a execução.
Exemplos = Python
Linguagens estáticas de tipo (o compilador resolve chamadas de método e compila referências):
Linguagens de tipo dinâmico (decisões tomadas na execução do programa):
a linguagem de tipo dinamicamente ajuda a prototipar rapidamente os conceitos de algoritmo sem a sobrecarga de pensar quais tipos de variáveis precisam ser usados (o que é uma necessidade no idioma de tipo estaticamente ).
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.
por 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
$
), array ( @
) e hash ( %
). O tipo de uma variável no Perl é conhecido no tempo de compilação e permanece o mesmo pelo resto da vida útil das variáveis.