Je lis Coders at Work, et il y a beaucoup de discussions sur les invariants. Pour autant que je l'ai compris, un invariant est une condition qui tient à la fois avant et après une expression. Ils sont, entre autres, utiles pour prouver que la boucle est correcte, si je me souviens bien de mon cours Logic.
Ma description est-elle correcte ou ai-je oublié quelque chose? Les avez-vous déjà utilisés dans votre programme? Et si oui, en ont-ils profité?
Dans la POO, un invariant est un ensemble d'assertions qui doivent toujours être vraies pendant la durée de vie d'un objet pour que le programme soit valide. Elle doit rester vraie de la fin du constructeur au début du destructeur chaque fois que l'objet n'exécute pas actuellement une méthode qui change son état.
Un exemple d'invariant pourrait être qu'exactement une des deux variables membres devrait être nulle. Ou que si l'un a une valeur donnée, alors l'ensemble des valeurs autorisées pour l'autre est ceci ou cela ...
J'utilise parfois une fonction membre de l'objet pour vérifier que l'invariant tient. Si ce n'est pas le cas, une assertion est émise. Et la méthode est appelée au début et à la sortie de chaque méthode qui change l'objet (en C++, ce n'est qu'une ligne ...)
Eh bien, ce que je vois dans ce fil est génial, mais j'ai une définition d'un "invariant" qui m'a été extrêmement utile au travail.
Un invariant est une règle logique qui doit être respectée tout au long de l'exécution de votre programme et qui peut être communiquée à un humain, mais pas à votre compilateur.
Cette définition est utile car elle clive les conditions en deux groupes: celles que le compilateur peut faire confiance à appliquer, et celles qui doivent être documentées, discutées, commentées ou autrement communiquées aux contributeurs afin qu'ils puissent interagir avec la base de code sans introduire de bogues. .
De plus, cette définition est utile car elle vous permet d'utiliser la généralisation "Les invariants sont mauvais".
Par exemple, le levier de vitesses dans une voiture à transmission manuelle est conçu pour éviter un invariant. Si je le voulais, je pourrais construire une transmission avec un levier pour chaque rapport. Ce levier peut être vers l'avant ("engagé") ou vers l'arrière ("débrayé"). Dans un tel système, j'ai créé un "invariant", qui pourrait être documenté comme tel:
"Il est essentiel que le rapport engagé actuellement soit désengagé avant qu'un rapport différent ne soit engagé. Le fait d'engager deux rapports en même temps entraînera des contraintes mécaniques qui déchireront la transmission. Désengagez toujours le rapport engagé avant d'en engager un autre."
Et donc, on pourrait blâmer les transmissions brisées sur une conduite bâclée. Les voitures modernes, cependant, utilisent un seul bâton qui pivote parmi les engrenages. Il est conçu de telle manière que, sur une voiture moderne à levier de vitesses, il n'est pas possible d'engager deux vitesses en même temps.
De cette façon, nous pourrions dire que la transmission a été conçue pour "supprimer l'invariant", car elle ne se permet pas d'être configurée mécaniquement d'une manière qui viole la règle logique.
Chaque invariant de ce type que vous supprimez de votre code est une amélioration, car il réduit la charge cognitive de travailler avec lui.
Basé sur la citation suivante de Coders At Work ...
Mais une fois que vous connaissez l'invariant qu'il maintient, vous pouvez voir, ah, si nous conservons cet invariant, nous obtiendrons le temps de recherche du journal.
... Je suppose que "invariant" = "condition que vous souhaitez maintenir pour assurer un effet souhaité".
Il semble que l'invariant ait deux sens qui diffèrent de manière subtile:
Donc, 1 est comme une assertion; 2 est comme un outil pour prouver l'exactitude, les performances ou d'autres propriétés - je pense. Voir le article Wikipedia pour un exemple de 2 (prouvant l'exactitude de la solution au puzzle MU).
En fait, un troisième sens de l'invariant est:
.3. Ce que le programme (ou module ou fonction) est censé faire; en d'autres termes, son objectif.
De la même interview de Coders At Work:
Mais ce qui rend les gros logiciels gérables, c'est d'avoir des invariants globaux ou des déclarations générales sur ce qu'il est censé faire et ce que les choses sont censées être vraies.
Un invariant (au sens commun) signifie certaines conditions qui doivent être vraies à un moment donné ou même toujours pendant l'exécution de votre programme. par exemple. PreConditions et PostConditions peuvent être utilisées pour affirmer certaines conditions qui doivent être vraies lorsqu'une fonction est appelée et lorsqu'elle revient. Les invariants d'objets peuvent être utilisés pour affirmer qu'un objet doit avoir un état valide tout au long de son existence. C'est le principe de la conception par contrat.
J'ai utilisé des invariants de manière informelle en utilisant des vérifications dans le code. Mais plus récemment, je joue avec le code bibliothèque de contrats pour .Net qui prend directement en charge les invariants.
Un invariant est comme une règle ou une hypothèse qui peut être utilisée pour dicter la logique de votre programme.
Par exemple, supposons que vous disposez d'une application logicielle qui assure le suivi des comptes d'utilisateurs. Supposons également que l'utilisateur puisse avoir plusieurs comptes, mais pour une raison quelconque, vous devez faire la différence entre le compte principal d'un utilisateur et les comptes "alias".
Cela peut être un enregistrement de base de données ou autre chose, mais pour l'instant, supposons que chaque compte d'utilisateur est représenté par un objet de classe.
class userAccount {private char * pUserName; char privé * pParentAccountUserName;
...}
Un invariant peut être l'hypothèse que si pParentAccountUserName est NULL ou vide, cet objet est le compte parent. Vous pouvez utiliser cet invariant pour distinguer différents types de compte. Il existe probablement de meilleures méthodes pour distinguer différents types de comptes d'utilisateurs, alors gardez à l'esprit que ce n'est qu'un exemple pour montrer comment un invariant peut être utilisé.
Issu d'un milieu physique, en physique, nous avons des invariants, qui sont essentiellement des quantités qui ne varient pas tout au long d'un calcul/simulation. Par exemple, en physique, pour un système fermé, l'énergie totale est conservée. Ou encore en physique, si deux particules entrent en collision, les fragments résultants doivent contenir exactement l'énergie avec laquelle ils ont commencé et exactement la même quantité de mouvement (une quantité vectorielle). Habituellement, il n'y a pas assez d'invariants pour spécifier totalement le résultat. Par exemple, dans la collision à 2 particules, nous avons quatre invariants, trois composantes de momentum et une composante d'énergie, mais le système a six degrés de liberté (six nombres pour décrire son état). Les invariants doivent être conservés avec une erreur d'arrondi, mais leur conservation ne prouve pas que la solution est correcte.
Donc, généralement, ces choses sont importantes en tant que vérifications de santé mentale, mais en elles-mêmes, elles ne peuvent pas prouver l'exactitude.