Dans Concepts in Programming Languages , John Mitchell écrit que la vérification de type statique est nécessairement conservatrice (trop stricte) en raison du problème d'arrêt. Il donne comme exemple:
if (complicated-expression-that-could-run-forever)
then (expression-with-type-error)
else (expression-with-type-error)
Quelqu'un peut-il fournir une réponse non artificielle qui serait vraiment une préoccupation pratique?
Je comprends que Java permet des conversions vérifiées dynamiquement pour des cas comme celui-ci:
if (foo instanceof Person) {
Person p = (Person) foo;
:
}
mais j'estime que la nécessité de cela est plus un déficit de langage / compilateur Java qu'un problème inter-langage.
programming-languages
compilers
type-checking
Ellen Spertus
la source
la source
Réponses:
Je l'ai toujours considéré comme une question de commodité, plutôt que de savoir si un algorithme peut ou non être exprimé du tout. Si je voulais vraiment exécuter des programmes comme celui de Mitchell, j'écrirais simplement le simulateur Turing Machine approprié dans mon langage typé.
L'astuce avec un système de type statique est d'offrir les bons types de flexibilité uniquement pour les cas où la flexibilité vous permet d'écrire du code plus facile à gérer.
Voici quelques exemples de techniques de structuration de programme qui sont parfois considérées comme plus faciles à gérer dans des langages typiquement statiques.
Génériques et conteneurs
Dans les langages typés avant ML (vers 1973) et CLU (vers 1974), il n'était pas difficile de créer un arbre de chaînes rouge-noir, un arbre d'entiers rouge-noir, un arbre de flotteurs rouge-noir ou un arbre rouge-noir d'éléments de type spécifique
Foo
. Il était cependant difficile (voire impossible) de créer une seule implémentation d'un arbre rouge-noir qui était à la fois vérifié statiquement et qui pouvait gérer n'importe lequel de ces types de données. Les moyens de contourner le problème étaient (1) de sortir complètement du système de type (par exemple: en utilisantvoid *
en C), (2) pour vous écrire une sorte de préprocesseur de macro puis écrire des macros qui produisent le code pour chaque type spécifique que vous souhaitez ou (3) utiliser l'approche Lisp / Smalltalk (et Java) pour vérifier le type de l'extract objet dynamiquement.ML et CLU ont introduit la notion, respectivement, de types paramétrés déduits et déclarés explicitement (statiques), qui vous permettent d'écrire des types de conteneurs génériques et statiquement typés.
Polymorphisme de sous-type
Dans les langues typées statiquement avant Simula67 (c. 1967) et Hope (c. 1977), il n'était pas possible à la fois de faire une répartition dynamique et de vérifier statiquement que vous aviez couvert le cas pour chaque sous-type. De nombreuses langues ont une certaine forme de syndicats marqués , mais il était de la responsabilité du programmeur de faire en sorte que leurs
case
ouswitch
déclarations, ou leurs tables de saut, couverts chaque balise possible.Les langages suivant le modèle Simula (C ++, Java, C #, Eiffel) fournissent des classes abstraites avec des sous-classes où le compilateur peut vérifier que chaque sous-classe a implémenté toutes les méthodes déclarées par la classe parente. Les langages suivant le modèle Hope (toutes les variantes ML, de SML / NJ à Haskell) ont des sous-types algébriques où le compilateur peut vérifier que chaque
typecase
instruction couvre tous les sous-types.Patching de singe et programmation orientée aspect
Les systèmes de type dynamiques facilitent beaucoup de techniques de prototypage. Dans les langues où les types sont représentés par des mappages de hachage des chaînes aux fonctions (par exemple, Python, Javascript, Ruby), il est assez facile de changer globalement le comportement de chaque module qui s'appuie sur un type particulier, simplement en modifiant dynamiquement le mappage de hachage représentant ce type.
Bien qu'il existe des moyens évidents d'utiliser le patch de singe pour rendre les programmes plus difficiles à maintenir, il existe également des moyens de l'utiliser pour le "bien" plutôt que pour le "mal". En particulier avec la programmation orientée aspect, on peut utiliser des techniques de type patching de singe pour faire des choses comme modifier le type de fichier pour pointer vers un système de fichiers virtualisé, permettant la construction d'infrastructures de test unitaire "gratuitement", ou modifier des types d'exceptions simples afin qu'ils imprimer des messages de journal chaque fois qu'ils sont capturés pour une meilleure débogage.
Contrairement aux génériques et au polymorphisme de sous-type où les idées clés de vérification statique étaient disponibles dans les années 1970, la vérification statique pour la programmation orientée aspect est (je pense) un domaine de recherche actif. Je ne sais pas grand-chose à ce sujet, sauf qu'il existe un langage appelé AspectJ depuis environ 2001.
la source