La nozione di invariante è strongmente legata agli "effetti collaterali". Credo che sia stato promosso dall'approccio di Design by Contract (DbC) di Bertrand Meyer per la progettazione di software.
DbC arricchisce i tipi di dati astratti (backbone delle classi) con 3 nozioni importanti, precondizioni , postcondizioni, invarianti . Si spiega facilmente quando ci si riferisce alle procedure, quindi cercherò di spiegarle in riferimento:
-
Una precondizione rappresenta la condizione che i dati di input per una procedura devono rispettare per chiamare quella procedura. Questa precondizione deve essere rispettata e applicata dal cliente di quella particolare procedura. Il progettista di procedure potrebbe tuttavia difendere da clienti che non rispettano la condizione preliminare affermando tale condizione come prime righe nella procedura. Ad esempio avendo un metodo double divide(double dividend, double divisor)
una precondizione potrebbe essere divisor != 0
.
-
Una postcondition rappresenta la condizione sui dati di output dopo il ritorno della procedura; è del tutto compito del progettista delle procedure rispettare questa condizione dopo aver rispettato la condizione preliminare; in uno stile di programmazione di difesa prima di tornare, la postcondizione può essere asserita.
-
Un invariante può essere considerato sia una precondizione che una postcondizione, ma con una comprensione diversa per la precondizione e la postcondizione dai concetti precedenti. Un invariante dice fondamentalmente che se l'input ha una condizione particolare soddisfatta prima che la procedura venisse chiamata, allora quella particolare condizione è valida dopo che la procedura è stata chiamata. Ad esempio, un invariante valido per una procedura boolean search(int term, int array[])
potrebbe dire che lo stato di array
prima della chiamata è uguale a quello che è dopo la chiamata.
Applicare invarianti sulle procedure (e non solo sulle procedure) è una cosa grandiosa poiché riduce effetti collaterali ; questo è utile dal momento che gli effetti collaterali sono un grande male nella programmazione. Una particolare procedura potrebbe cambiare lo stato degli argomenti di input, oppure cambiare lo stato di alcune variabili globali o dipendere da alcune variabili globali; questo potrebbe portare a situazioni sgradevoli in cui due chiamate identiche sulla stessa procedura (con lo stesso input) potrebbero produrre output diversi. Ciò porta a conoscere la cronologia delle chiamate ed è molto difficile eseguire il debug soprattutto in un contesto di multithreading.