Penso che il dilemma sia chiaro: stiamo parlando di Programmazione Strutturata mica di quisquilie. E se qualcuno sta pensando "ma la programmazione strutturata è superata", oppure "con la OOP l'approccio è completamente diverso", lo fermo subito. Qui si parla del C, il padre (o perlomeno lo zio) di tutti i linguaggi moderni, e il C è un linguaggio strutturato. Punto e basta. E se pensate che il C e la Programmazione Strutturata sono superati vi conviene prendervi una pausa di riflessione...
E allora ? Va beh, vediamo un esempio così ci chiariamo le idee. Scriviamo una funzione che apre un file, estrae la prima linea, processa i dati della linea ed esce. Come sempre si potrebbe scrivere in varie migliaia di modi diversi, ma noi isoliamo i due che ci servono per l'esempio (beh, isoliamo anche un terzo modo, ma quello è per finire in bellezza il post). Vediamo prima il tipo Single-Exit:
int readFile( char *path) { char *line = NULL; size_t len = 0; int retcode; // apro il file in argomento FILE *fp; if (fp = fopen(path, "r")) { // leggo il file if (getline(&line, &len, fp) != -1) { // test contenuto file if (!strncmp(line, "output=", 7)) { // processa dati // ... retcode = 0; // proc. OK: set retcode=OK } else retcode = -3; // str err: set retcode=err free(line); // libera risorse } else retcode = -2; // getline err: set retcode=err fclose(fp); // libera risorse } else retcode = -1; // fopen err: set retcode=err // esce con il retcode settato return retcode; }E adesso possiamo passare a analizzare il suo perfetto equivalente in modalità Multiple-Exit, ossia:
int readFile( char *path) { char *line = NULL; size_t len = 0; // apro il file in argomento FILE *fp; if ((fp = fopen(path, "r")) == NULL) { // esce con errore return -1; } // leggo il file if (getline(&line, &len, fp) == -1) { // libera risorse ed esce con errore fclose(fp); return -2; } // test contenuto file if (strncmp(line, "output=", 7)) { // libera risorse ed esce con errore fclose(fp); free(line); return -3; } // processa dati // ... // proc. OK: libera risorse ed esce con OK fclose(fp); free(line); return 0; }Quale è il tipo migliore ? Beh, per me (e lui) è il tipo Single-Exit, ma, c'è da dire che il partito del Multiple-Exit è numeroso e formato (anche) da gente molto preparata.
E allora dove sta la verità, forse nel mezzo ? No, dire sempre che verità sta nel mezzo è la scusa degli indecisi. Io scelgo la soluzione con lo stile migliore, la più bella e facile da leggere, e, aggiungo, quella che ti dà un controllo maggiore mentre la scrivi: nel tipo Single-Exit è più difficile dimenticarsi di liberare le risorse giuste nel momento giusto (pensate a un programma più complesso, non all'esempio). E, inoltre, il tipo Single-Exit è anche più facile da leggere e debuggare (provare per credere, ma sempre con un caso più complesso).
Potrei fare un eccezione: quando con il tipo Single-Exit il livello di annidamento diventa troppo alto forse si potrebbe fare un ibrido: mettere i test basici (tipo "il parametro passato è nullo ?") all'inizio con i relativi return, e poi seguire in modo Single-Exit (ma, se alla fine il codice risultante non vi convince, magari è meglio se spezzate in due la funzione).
Comunque, sono meno radicale di quello che sembra: tra il codice che ho scritto nei miei trascorsi c'è (basta guardare qui) del codice Multiple-Exit o ibrido. Il fatto è che bisogna essere un po' elastici: programmare (bene) è un'arte, e troppe restrizioni non giovano all'espressività.
Come preannunciato chiudiamo in bellezza con il terzo tipo: anche la funzione seguente funziona, ed è un perfetto equivalente delle precedenti:
int readFile3( char *path) { char *line = NULL; size_t len = 0; // faccio tutto in una botta sola FILE *fp; if ((fp = fopen(path, "r")) && (getline(&line, &len, fp) != -1) && !strncmp(line, "output=", 7)) { // processa dati // ... // dati processati: libera risorse ed esce con OK fclose(fp); free(line); return 0; } else { // libera risorse ed esce con errore if (fp) fclose(fp); if (line) free(line); return -1; } }Ecco, se vi viene in mente di scrivere una funzione in quest'ultima maniera (magari mettendo ancora più test nello stesso if) rilassatevi, prendetevi un periodo di riposo, leggete qualche libro interessante e poi riprovateci con la testa finalmente sgombra da cattivi pensieri: magari (spero) non vi verrà più in mente di scriverla così.
Ciao e al prossimo post.
Nessun commento:
Posta un commento