The debate between defensive/exception handling I find very interesting.
Sembra che tu stia insinuando che questi due concetti sono in disaccordo l'uno con l'altro. Non lo sono. Di fatto, una forma comune di programmazione difensiva sta controllando gli argomenti di una funzione e generando eccezioni se non sono validi.
But at the same time, if that happens I would prefer if the compiler /stops/ the program and says, "You raised an error." So I can fix it.
Uno dei vantaggi del lancio di eccezioni è che per impostazione predefinita interromperanno il programma.
Un confronto più utile sarebbe costituito dai codici di errore rispetto alle eccezioni. Questi sono entrambi i meccanismi per affrontare i fallimenti inevitabili. In altre parole, i guasti che non sono il risultato di un errore di programmazione, ma sono qualcosa che il programmatore semplicemente non può impedire. Esempi comuni includono l'esaurimento della memoria, un determinato file non esistente o che non consente l'accesso in scrittura o un timeout della richiesta di rete.
Prima delle eccezioni, questi tipi di errori erano solitamente indicati da un codice di errore restituito dalla funzione che potrebbe inevitabilmente fallire. I problemi con questo approccio sono: 1) È facile per un programmatore semplicemente non controllare mai i codici di errore, lasciando una lista quasi infinita di bug rari e sottili con conseguenze completamente imprevedibili. 2) Poiché è solo un numero intero, non si ottengono molte informazioni sul perché si è verificato l'errore. 3) In molti casi, il luogo in cui viene chiamata la potente funzione di non funzionamento non è un luogo in cui un guasto può essere ragionevolmente recuperato. Ciò richiede che il codice di errore sia "passato di nuovo" allo stack di chiamate da ogni singola funzione che può chiamarlo direttamente o indirettamente. Inutile dire che questo è soggetto a errori.
Le eccezioni erano intese come soluzione a questi problemi. Quando viene lanciata un'eccezione, è impossibile per il programmatore ignorarla accidentalmente; o fanno di tutto per catturarlo e gestirlo, o il programma si blocca. Le eccezioni tendono anche a contenere molte più informazioni sull'errore rispetto a un singolo intero. E non è necessario scrivere alcun codice per consentire alle eccezioni di propagarsi attraverso una funzione; continuano a salire finché non raggiungono il codice che in realtà vuole gestirli.
Quindi i posti migliori per usare le eccezioni sono quando si ha un potenziale fallimento inevitabile che sarebbe pericoloso ignorare e in genere è difficile o impossibile da recuperare nel luogo in cui si verifica.
Come esempio semplice e forse un po 'estremo, considera ciò che accade quando esaurisci la memoria. Qualsiasi funzione che crea oggetti può potenzialmente esaurire la memoria. Se dovessi provare a gestire questi errori correttamente con i codici di errore, quasi ogni singola funzione non banale nel tuo programma dovrebbe ricordare di controllare se l'allocazione fallita, controllare se qualcuna delle altre funzioni ha fallito la sua chiamata e restituire l'uscita codice di memoria quando lo fanno. E non esiste un modo corretto per gestire il problema oltre a mostrare all'utente un messaggio di errore "Memoria insufficiente" (che è tipicamente possibile solo vicino alla parte superiore del programma). Quindi il fatto che C ++ gestisca questo tramite un'eccezione consente di risparmiare una quantità enorme di codice estremamente noioso e soggetto a errori; è sufficiente scrivere il codice per mostrare il messaggio di errore "Memoria insufficiente".
Talvolta le eccezioni sono utili anche per il rilevamento e la rapida interruzione degli errori logici. Supponi di scrivere una funzione radice quadrata. Funziona solo su numeri positivi, ma il compilatore non può impedire alle persone di passare un numero negativo. Puoi semplicemente ignorare questo problema e dichiarare che chiunque faccia questo errore sta invocando un comportamento indefinito (vedi "design by contract"). Ma la programmazione difensiva è spesso una buona cosa e vorremmo che la nostra API fosse un po 'più user-friendly di così. Non è possibile restituire un codice di errore poiché si prevede che la funzione radice quadrata restituisca una radice quadrata. È possibile registrare un messaggio di errore, ma questo non arresta immediatamente il programma in modo che il programmatore non possa notarlo. Se si lancia un'eccezione, ciò interromperà immediatamente il programma e visualizzerà un messaggio di errore chiaro, quindi di solito è una buona scelta. Molte lingue hanno anche una sorta di meccanismo di "asserzione" che è anche una buona soluzione per questo. Le asserzioni si comportano in modo molto simile alle eccezioni, tranne per il fatto che non puoi prenderle, quindi sono in qualche modo più semplici.