Pourquoi ne cherchons-nous pas davantage vers des garanties de temps de compilation?

12

J'adore tout ce qui est temps de compilation et j'adore l'idée qu'une fois que vous compilez un programme, de nombreuses garanties sont faites concernant son exécution. De manière générale, un système de type statique (Haskell, C ++, ...) semble donner des garanties de compilation plus fortes que tout système de type dynamique.

D'après ce que je comprends, Ada va encore plus loin en ce qui concerne la vérification du temps de compilation et est capable de détecter une plus grande gamme de bogues avant l'exécution. Il est également considéré comme assez sûr, étant donné qu'à un moment donné, il a été choisi pour des domaines délicats (lorsque les erreurs de programmation peuvent coûter des vies humaines).

Maintenant, je me demande: si des garanties statiques plus fortes conduisent à un code plus documenté et plus sûr, alors pourquoi ne cherchons-nous pas davantage dans cette direction?

Un exemple de quelque chose qui semble manquer serait un langage qui, au lieu de définir un inttype générique ayant une plage déterminée par le nombre de bits de l'architecture sous-jacente, pourrait avoir des plages (dans l'exemple suivant, Int [a..b]décrit un type entier entre a et b inclus):

a : Int [1..24]
b : Int [1..12]
a + b : Int [2..36]
a - b : Int [-11..23]
b - a : Int [-23..11]

ou (en prenant cela à Ada):

a : Int [mod 24]
b : Int [mod 24]
a + b : Int [mod 24]

Ce langage sélectionnerait le meilleur type sous-jacent pour la plage et effectuerait une vérification du temps de compilation sur les expressions. Ainsi, par exemple, étant donné:

a : Int [-3..24]
b : Int [3..10]

ensuite:

a / b

ne sera jamais défini.

Ce n'est qu'un exemple, mais j'ai l'impression qu'il y a beaucoup plus que nous pouvons appliquer au moment de la compilation. Alors, pourquoi semble-t-il si peu de recherches à ce sujet? Quels sont les termes techniques qui décrivent cette idée (pour que je puisse trouver plus d'informations sur ce sujet)? Quelles sont les limites?

Chaussure
la source
2
Pascal a des types de sous-gamme entiers (c'est-à-dire des années 1960), mais malheureusement la plupart des implémentations ne les vérifient qu'au moment de l'exécution (int (-1..4) est compatible avec affectation int (100..200) au moment de la compilation). Les avantages sont limités et la programmation basée sur les contrats étend l'idée dans une meilleure direction (Eiffel, par exemple). Des langages comme C # essaient d'obtenir certains de ces avantages avec des attributs, je ne les ai pas utilisés, donc je ne sais pas à quel point ils sont utiles dans la pratique.
1
@ Ӎσᶎ: Les attributs en C # ne sont que des classes de métadonnées, donc toute validation des données se produira au moment de l'exécution.
Robert Harvey
8
Comment savez-vous qu'il y a peu de recherches à ce sujet? Essayez de googler dependent typeou refinement type.
Phil
3
Je suis d'accord que la prémisse semble être erronée; c'est certainement un domaine de recherche actif. Le travail n'est jamais terminé . Par conséquent, je ne vois pas très bien comment répondre à cette question.
Raphael
1
@Robert Harvey: Le fait que l'ADA offre plus de garanties ne signifie pas que le compilateur détectera toutes les erreurs, il ne fera que rendre les erreurs moins probables.
Giorgio

Réponses:

11

Je ne suis pas en mesure de dire combien plus la recherche devrait être fait sur le sujet, mais je peux vous dire qu'il y a la recherche se fait, par exemple , le XT Verisoft programme financé par le gouvernement allemand.

Les concepts que je pense que vous recherchez sont appelés vérification formelle et programmation basée sur les contrats , où ce dernier est une manière conviviale pour le programmeur de faire le premier. Dans la programmation basée sur les contrats, vous écrivez d'abord votre code normalement, puis vous insérez les soi-disant contrats dans le code. Un langage facilement utilisable qui est basé sur ce paradigme est Spec # de Microsoft Research, et l' extension fonctionnellement similaire mais légèrement moins jolie Code Contracts pour C # que vous pouvez essayer en ligne (ils ont également des outils similaires pour d'autres langues, consultez rise4fun ). Le "int avec type de plage" que vous avez mentionné serait reflété par deux contrats dans une fonction:

Contract.Requires(-3 <= a && a <= 24);
Contract.Requires( 3 <= b && b <= 10);

Si vous voulez appeler cette fonction, vous devez alors utiliser des paramètres garantis pour répondre à ces critères, ou vous obtenez une erreur de temps de compilation. Les contrats ci-dessus sont très simples, vous pouvez insérer presque toutes les hypothèses ou exigences concernant les variables ou les exonérations et leur relation auxquelles vous pourriez penser et le compilateur vérifiera si chaque exigence est couverte par une hypothèse ou quelque chose qui peut être assuré, c'est-à-dire dérivé des hypothèses. C'est pourquoi d'où vient le nom: l'appelé fait des exigences , l'appelant s'assure que celles-ci sont respectées - comme dans un contrat commercial.

P(x1,x2,...,xn)nPest utilisé. Du côté CS, ces deux sont les parties critiques du processus - la génération de conditions de vérification est délicate et SMT est un problème NP-complet ou indécidable, selon les théories considérées. Il existe même un concours pour les solveurs SMT, il y a donc certainement des recherches à ce sujet. De plus, il existe des approches alternatives à l'utilisation de SMT pour la vérification formelle comme l'énumération de l'espace d'état, la vérification de modèle symbolique, la vérification de modèle borné et bien d'autres qui sont également à l'étude, bien que SMT soit, afaik, actuellement l'approche la plus "moderne".

Concernant les limites de l'idée générale:

  • Comme indiqué précédemment, la preuve de l'exactitude du programme est un problème de calcul difficile, il peut donc être possible que la vérification du temps de compilation d'un programme avec des contrats (ou une autre forme de spécification) prenne beaucoup de temps ou soit même impossible. Appliquer une heuristique qui fonctionne bien la plupart du temps est la meilleure solution.
  • Plus vous spécifiez sur votre programme, plus la probabilité d'avoir des bogues dans la spécification elle-même est élevée . Cela peut conduire à des faux positifs (la vérification du temps de compilation échoue même si tout est exempt de bogues) ou à la fausse impression d'être sûr, même si votre programme a encore des bogues.
  • La rédaction de contrats ou de spécifications est un travail vraiment fastidieux et la plupart des programmeurs sont trop paresseux pour le faire. Essayez d'écrire un programme C # avec des contrats de code partout, après un certain temps vous penserez "allez, est-ce vraiment nécessaire?". C'est pourquoi la vérification formelle n'est généralement utilisée que pour la conception matérielle et les systèmes critiques pour la sécurité, comme les logiciels contrôlant les avions ou les automoteurs.

Une dernière chose à mentionner qui ne correspond pas tout à fait à l'explication ci-dessus est un domaine appelé "Théorie de la complexité implicite", par exemple cet article . Il vise à caractériser les langages de programmation dans lesquels chaque programme que vous pouvez écrire appartient à une classe de complexité spécifique, par exemple P. Dans un tel langage, chaque programme que vous écrivez est automatiquement «garanti» d'être à l'exécution polynomiale, qui peut être «vérifié» au moment de la compilation en compilant simplement le programme. Je ne connais cependant pas de résultats pratiquement utilisables de cette recherche, mais je suis également loin d'être un expert.

Stefan Lutz
la source
Ne devrait-il pas être possible de générer des types ou des contrats dépendants à partir d'une combinaison d'exemples de test et de code non typé, compte tenu d'une certaine «stratégie» que vous pouvez choisir en fonction de votre projet?
aoeu256