Je comprends "invariant" dans son sens littéral. Je les reconnais aussi lorsque je tape le code. Mais je ne pense pas comprendre l'importance de ce terme dans le contexte de l'informatique.
Chaque fois que je lis des conversations\White Papers sur la conception de la langue des programmeurs célèbres\informaticiens, le terme "invariant" ne permet de sauter comme un jargon; Et c'est la partie que je ne comprends pas. Qu'est-ce qui est si spécial à ce sujet?
Un algorithme est un processus reproductible. S'il est répétable, il doit avoir des attributs qui ne changent pas avec la répétition. Ce sont vos invariants. Les invariants sont combinés avec et/ou fonctionnent sur les données variables (potentiellement) qui seront introduites dans votre algorithme.
Ainsi, tout le point de programmation est d'identifier ce qui ne varie pas - c'est essentiellement votre programme.
Dans le programme orienté objet, il existe une notion que chaque objet devrait bien faire une seule chose. Cela signifie essentiellement que (pour OOP basée sur la classe) une classe définit les invariants pour un seul algorithme, ainsi que des détenteurs de lieu (variables) pour toute variante de données que ses objets pourraient avoir besoin. Idéalement à OO, vous allez isoler ce qui varie autant que possible, de sorte que chaque objet soit principalement invariant.
La notion d'invariant est fortement liée aux "effets secondaires". Je crois que cela a été promu par l'approche de la conception de la conception de Bertrand Meyer (DBC) 'pour la conception de logiciels.
DBC enrichit des types de données abstraits (backbone des classes) avec 3 notions importantes, conditions préalables, postconditions, invariants. Il est facilement expliqué lors de la référence aux procédures, donc je vais essayer d'expliquer en référence avec elle:
A Préconfection représente les données d'entrée de condition pour une procédure doit respecter afin d'appeler cette procédure. Cette condition préalable doit être respectée et appliquée par le client de cette procédure particulière. Le concepteur de procédure peut toutefois défendre des clients qui ne respectent pas la condition préalable en affirmant que la condition de première ligne dans la procédure. Par exemple, avoir une méthode double divide(double dividend, double divisor)
une condition préalable peut être divisor != 0
.
A postcondition représente la condition d'une condition sur les données de sortie après la procédure de retour; C'est entièrement le travail du concepteur de procédure à respecter cette post-conciliation à condition que la condition préalable soit respectée; Dans un style de programmation de la défense avant de retourner, la postcondition peut être affirmée.
An invariant Peut être considéré comme une condition préalable et une compréhension, mais avec une compréhension différente pour la préconditionnement et la postcondition des concepts ci-dessus. Un invariant dit essentiellement que le si l'entrée a une condition particulière remplie avant que la procédure soit appelée, cette condition particulière est valide après que la procédure soit appelée. Par exemple, un invariant valide pour une procédure boolean search(int term, int array[])
peut dire que l'état de array
avant l'appel est identique à celui de l'appel.
L'application des invariants sur les procédures (et non seulement les procédures) est une bonne chose puisqu'elle réduit Effets secondaires; Ceci est utile depuis que les effets secondaires sont un grand mal dans la programmation. Une procédure particulière pourrait modifier l'état des arguments d'entrée ou modifier l'état de certaines variables globales ou dépendre de certaines variables globales; Cela pourrait conduire à des situations désagréables où deux appels identiques sur la même procédure (avec la même entrée) pourraient donner des sorties différentes. Cela conduit à connaître l'histoire des appels et est très difficile à déboguer, en particulier dans un contexte multithreading.
Un invariant est une propriété logique préservée par certaines opérations.
Vous avez besoin d'invariants pour raisonner sur les boucles. Puisque vous ne savez pas auparavant combien d'itérations il y aura (ou si vous n'auriez pas besoin d'une boucle), chaque itération doit préserver l'invariant, de sorte que, à la fin, vous pouvez prouver des biens utiles sur la boucle.
Vous avez besoin d'invariants pour raisonner sur les propriétés des données encapsulées. Souvent, les différentes données à l'intérieur d'un module ou d'un objet doivent satisfaire certaines propriétés pour un fonctionnement correct (par exemple, une liste représentant un ensemble doit toujours être triée). Vous voulez que chaque fonction ou une méthode fonctionnant sur les données conserve ces propriétés, de sorte qu'elles soient des invariants.
D'après ce que je sais que l'importance de l'invariant vient du fait qu'il s'agit du bloc de construction de prouver qu'un algorithme calculera une certaine fonction. Par exemple, vous avez développé un nouvel algorithme de tri, mais comment pouvez-vous être si sûr qu'il trie vraiment avec chaque entrée ou avec chaque sortie correcte. L'étape suivante consiste à construire des invariants qui correspondent à la circulation de l'algorithme et à prouver qu'il utilise les invariants.