As linguagens de tipo dinâmico que eu conheço nunca deixam os desenvolvedores especificarem os tipos de variáveis ou, pelo menos, têm um suporte muito limitado para isso.
O JavaScript, por exemplo, não fornece nenhum mecanismo para impor tipos de variáveis quando for conveniente. PHP permitem especificar alguns tipos de argumentos de método, mas não há maneira de usar tipos nativos ( int
, string
, etc.) para os argumentos, e não há nenhuma maneira de impor tipos para outra coisa senão argumentos.
Ao mesmo tempo, seria conveniente ter a opção de especificar, em alguns casos, o tipo de uma variável em um idioma digitado dinamicamente, em vez de fazer a verificação do tipo manualmente.
Por que existe essa limitação? É por razões técnicas / de desempenho (suponho que seja no caso do JavaScript) ou apenas por razões políticas (que é, acredito, o caso do PHP)? Esse é o caso de outras linguagens de tipo dinâmico que eu não conheço?
Edit: seguindo as respostas e os comentários, aqui está um exemplo para um esclarecimento: digamos que temos o seguinte método no PHP simples:
public function CreateProduct($name, $description, $price, $quantity)
{
// Check the arguments.
if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
Com alguns esforços, isso pode ser reescrito como (também consulte Programação por contratos em PHP ):
public function CreateProduct($name, $description, $price, $quantity)
{
Component::CheckArguments(__FILE__, __LINE__, array(
'name' => array('value' => $name, 'type' => VTYPE_STRING),
'description' => array('value' => $description, 'type' => VTYPE_STRING),
'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
));
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
Mas o mesmo método seria escrito da seguinte forma se o PHP opcionalmente aceitasse tipos nativos para argumentos:
public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
// Check the arguments.
if (!$name) throw new Exception('The name argument cannot be an empty string.');
if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
if ($price < 0) throw new Exception('The price argument cannot be less than zero.');
// We can finally begin to write the actual code.
// TODO: Implement the method here.
}
Qual é o mais curto para escrever? Qual é mais fácil de ler?
fonte
Respostas:
O objetivo de ter uma digitação estática é a capacidade de provar estaticamente que seu programa está correto em relação aos tipos (nota: não totalmente correto em todos os sentidos). Se você tiver um sistema de tipo estático, poderá detectar erros de tipo na maioria das vezes.
Se você tiver apenas informações de tipo parcial, poderá verificar apenas as pequenas partes de um gráfico de chamada onde as informações de tipo estão completas. Mas você gastou tempo e esforço para especificar informações de tipo para peças incompletas, onde elas não podem ajudá-lo, mas podem dar uma falsa sensação de segurança.
Para expressar informações de tipo, você precisa de uma parte do idioma que não possa ser excessivamente simples. Em breve você descobrirá que informações como
int
não são suficientes; você vai querer algo comoList<Pair<Int, String>>
tipos paramétricos, etc. Isso pode ser bastante confuso, mesmo no caso bastante simples de Java.Então, você precisará manipular essas informações durante a fase de tradução e a fase de execução, porque é bobagem verificar apenas erros estáticos; o usuário espera que as restrições de tipo sempre sejam mantidas, se especificadas. Os idiomas dinâmicos não são tão rápidos quanto são e essas verificações retardarão ainda mais o desempenho. Uma linguagem estática pode gastar muito esforço verificando os tipos, porque só faz isso uma vez; uma linguagem dinâmica não pode.
Agora imagine adicionar e manter tudo isso apenas para que as pessoas às vezes usem esses recursos opcionalmente , detectando apenas uma pequena fração dos erros de tipo. Eu não acho que vale a pena o esforço.
O ponto principal das linguagens dinâmicas é ter uma estrutura muito pequena e muito maleável, na qual você possa facilmente fazer coisas muito mais envolvidas quando executadas em uma linguagem estática: várias formas de correção de macacos usadas para metaprogramação, zombaria e testes, substituição dinâmica de código, etc. Smalltalk e Lisp, ambos muito dinâmicos, levaram ao extremo a enviar imagens de ambiente em vez de construir a partir da fonte. Mas quando você quiser garantir que determinados caminhos de dados sejam seguros para o tipo, adicione asserções e escreva mais testes de unidade.
fonte
Na maioria das linguagens dinâmicas, você pode pelo menos testar dinamicamente o tipo de um objeto ou valor.
E existem inferenciadores de tipo estático, verificadores e / ou aplicadores para algumas linguagens dinâmicas: por exemplo
E o Perl 6 suporta um sistema de tipos opcional com digitação estática.
Mas acho que o ponto principal é que muitas pessoas usam linguagens dinamicamente porque são tipadas dinamicamente e, para elas, a digitação estática opcional é muito "hum hum". E muitas outras pessoas as usam porque são "fáceis de usar por não programadores", principalmente como conseqüência da digitação dinâmica da natureza perdoadora. Para eles, a digitação opcional é algo que eles não entenderão ou não se incomodarão em usar.
Se você fosse cínico, poderia dizer que a digitação estática opcional oferece o pior dos dois mundos. Para um fanático do tipo estático, ele não evita todas as falhas do tipo dinâmico. Para um fã do tipo dinâmico, ainda é uma jaqueta reta ... embora com as tiras não esticadas.
fonte
O Javascript planejou incluir alguma digitação estática opcional e parece que muitas linguagens dinâmicas maduras estão indo dessa maneira.
O motivo é que, quando você codifica pela primeira vez, deseja ser rápido e digitado dinamicamente. Depois que seu código estiver sólido, funcionando e tiver muitos usos, você deseja bloquear o design para reduzir erros. (isso é benéfico para usuários e desenvolvedores, pois o primeiro receberá uma verificação de erro em suas chamadas e o segundo não interromperá as coisas acidentalmente.
Faz algum sentido para mim, já que geralmente encontro muita verificação de tipo no início de um projeto, muito pouco no final de sua vida útil, independentemente do idioma que eu use;).
fonte
Objetos Python fazer ter um tipo.
Você especifica o tipo ao criar o objeto.
Na verdade, uma verificação manual do tipo no Python quase sempre é uma perda de tempo e código.
É simplesmente uma prática ruim escrever código de verificação de tipo no Python.
Se um tipo inapropriado foi usado por algum sociopata mal-intencionado, os métodos comuns do Python criarão uma exceção comum quando o tipo não for apropriado.
Você não escreve código, seu programa ainda falha com a
TypeError
.Existem casos muito raros em que você deve determinar o tipo em tempo de execução.
Como não é uma "limitação", a pergunta não é verdadeira.
fonte
Na maioria das vezes, você não precisa, pelo menos não no nível de detalhe que está sugerindo. No PHP, os operadores que você usa deixam perfeitamente claro o que você espera que os argumentos sejam; é um pouco de supervisão de design, porém, que o PHP converterá seus valores, se possível, mesmo quando você passa uma matriz para uma operação que espera uma string e, como a conversão nem sempre é significativa, às vezes você obtém resultados estranhos ( e é exatamente aqui que as verificações de tipo são úteis). Fora isso, não importa se você adiciona números inteiros
1
e /5
ou strings"1"
e"5"
- o simples fato de estar usando o método+
O operador sinaliza para o PHP que você deseja tratar os argumentos como números, e o PHP obedecerá. Uma situação interessante é quando você recebe resultados da consulta do MySQL: Muitos valores numéricos são simplesmente retornados como strings, mas você não notará, pois o PHP os projeta para você sempre que os trata como números.O Python é um pouco mais rígido quanto a seus tipos, mas, diferentemente do PHP, o Python teve exceções desde o início e o utiliza de forma consistente. O paradigma "mais fácil pedir perdão do que permissão" sugere apenas executar a operação sem verificação de tipo e depender de uma exceção ser levantada quando os tipos não fazem sentido. A única desvantagem disso em que consigo pensar é que, às vezes, você descobre que em algum lugar um tipo não corresponde ao que você espera, mas encontrar o motivo pode ser entediante.
E há outro motivo a considerar: os idiomas dinâmicos não têm um estágio de compilação. Mesmo se você tiver restrições de tipo, elas poderão ser acionadas apenas no tempo de execução, simplesmente porque não há tempo de compilação . Se suas verificações levarem a erros de tempo de execução, é muito mais fácil modelá-las de acordo: Como verificações explícitas (como
is_XXX()
em PHP outypeof
javascript) ou lançando exceções (como o Python). Funcionalmente, você tem o mesmo efeito (um erro é sinalizado no tempo de execução quando uma verificação de tipo falha), mas ele se integra melhor ao restante da semântica do idioma. Simplesmente não faz sentido tratar erros de tipo fundamentalmente diferentes de outros erros de tempo de execução em uma linguagem dinâmica.fonte
Você pode estar interessado em Haskell - o sistema de tipos infere os tipos do código e você também pode especificar os tipos.
fonte
Como as outras respostas mencionaram, há duas abordagens para digitar ao implementar uma linguagem de programação.
Ambas as abordagens são válidas e a utilização depende, em parte, de considerações técnicas, como desempenho, e, em parte, de razões políticas, como o mercado-alvo do idioma.
fonte
Primeiro de tudo, as linguagens dinâmicas foram criadas principalmente para facilitar o uso. Como você mencionou, é muito bom realizar a conversão de tipos automaticamente e fornecer menos despesas gerais. Mas, ao mesmo tempo, falta problemas de desempenho.
Você pode ficar com os idiomas dinâmicos, caso não se preocupe com o desempenho. Digamos, por exemplo, que o JavaScript seja mais lento quando for necessário realizar muitas conversões de tipo no seu programa, mas isso ajuda a reduzir o número de linhas no seu código.
E para ser mencionado, existem outras linguagens dinâmicas que permitem ao programador especificar o tipo. Por exemplo, o Groovy é uma das famosas linguagens dinâmicas que são executadas na JVM. E tem sido muito famoso nos últimos dias mesmo. Observe que o desempenho do Groovy é igual ao Java.
Espero que ajude você.
fonte
Simplesmente não faz sentido fazê-lo.
Por quê?
Como o sistema de tipos de DTLs é precisamente tal que os tipos não podem ser determinados em tempo de compilação. Portanto, o compilador não conseguiu nem verificar se o tipo especificado faria sentido.
fonte
Dê uma olhada em Go, na superfície, ele é estaticamente digitado, mas esses tipos podem ser interfaces que são essencialmente dinâmicas.
fonte