Qu'est-ce qu'un exemple non artificiel de vérification de type statique trop conservatrice?

9

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.

Ellen Spertus
la source
2
L'exemple Java que vous avez donné est un exemple non artificiel de vérification de type statique trop conservatrice. Autrement dit: la réponse dépend du type de système auquel vous pensez. Pour tout exemple que nous arrivons, il y aura toujours un système de type qui peut gérer cet exemple (le système de type n'est pas trop conservateur sur cet exemple). Pour tout type de système, nous pouvons toujours trouver un exemple où il est trop conservateur. Donc, je pense que vous devez spécifier le système de type. Si le système de type Java n'est pas ce à quoi vous pensiez, y a-t-il quelque chose de plus spécifique auquel vous pensiez? Inférence de type ML?
DW
on pourrait soutenir que l'exemple est celui d' une analyse de code statique étant «conservatrice», et non une vérification de type nec. il serait utile de définir «conservateur» . sans doute tous les systèmes de type statique seront "conservateurs" par rapport aux systèmes dynamiques parce que les premiers sont plus stricts au moment de la compilation par définition. cependant, on pourrait affirmer que ni l'un ni l'autre n'est plus strict à l' exécution car la vérification dynamique peut également renvoyer des erreurs similaires (basées sur le type). et soit dit en passant, les conversions vérifiées dynamiques à l'exécution dans les langues ne sont pas une lacune , elles le sont dans la plupart des langues vérifiées statiquement, peut-être prouvées nca.
vzn

Réponses:

7

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 caseou switchdé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 typecaseinstruction 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.

Logique errante
la source