Se una funzione contiene solo un interruttore, è una cattiva pratica sostituire l'interruzione; dichiarazioni con ritorno; affermazioni?

2

Diciamo che ho una funzione che accetta un argomento, esegue un'azione in base al valore di tale argomento e restituisce false se non esiste alcuna azione per quel valore. (pseudo-codice):

bool executeSomeAction(someValue) {
    switch (someValue) {
    case shouldDoAction1:
        action1();
        break;

    case shouldDoAction2:
        action2();
        break;

    default:
        return false;
    }
    return true;
}

È una cattiva pratica scrivere in questo modo:

bool executeSomeAction(someValue) {
    switch (someValue) {
    case shouldDoAction1:
        action1();
        return true;

    case shouldDoAction2:
        action2();
        return true;

    default:
        return false;
    }
}

Modifica: non vedo come questo è un duplicato della domanda collegata, sto chiedendo della migliore pratica di scrivere una funzione con una singola istruzione switch, non sto affatto chiedendo di usare un singolo o più dichiarazioni di reso.

    
posta Kevin 28.09.2016 - 10:02
fonte

4 risposte

3

Non è assolutamente una cattiva pratica. Uso il pattern di ritorno diretto piuttosto per i metodi factory / strategy, dove diverse classi implementano la stessa interfaccia e una specifica implementazione viene recuperata in base ad alcune strategie.

Non usando il ritorno diretto, dovendo usare l'istruzione break e magari avere un singolo punto di ritorno da una funzione può lasciare lo sviluppatore che legge il codice chiedersi, se una variabile è o non è alterata in un altro punto del funzione. Se dovessi tornare immediatamente, la conclusione è molto semplice: la funzione termina.

Se ti trovi in un posto dove puoi tornare in sicurezza da una funzione, fallo.

Io sceglierei l'opzione 2 su 1, o anche meglio, cambia le funzioni action1 e action2 per restituire valori booleani stessi e indirizza return action1() o return action2() rispettivamente.

bool executeSomeAction(someValue)
{
    switch (someValue)
    {
    case shouldDoAction1:
        return action1();
    case shouldDoAction2:
        return action2();
    default:
        return false;
    }
}
    
risposta data 28.09.2016 - 10:49
fonte
1

Non credo che sia una cattiva pratica scrivere questo codice. Al contrario, credo che sia un'ottima pratica . Se l'esecuzione raggiunge un punto in cui la funzione non ha più nulla da fare, return ing è immediatamente la cosa migliore e più ovvia da fare. Se leggo return , so immediatamente cosa sta succedendo. Se leggo break , prima devo controllare dove il flusso di controllo salta dopo.

Detto questo, sarei coerente. O ogni case (incluso default ) dovrebbe contenere un return o nessuno. Penso che il missaggio come nel tuo primo frammento sia ancora meno leggibile. Poiché un switch è già difficile da seguire, cerco di mantenerlo il più semplice possibile (minimo sorprese per il lettore).

    
risposta data 28.09.2016 - 10:53
fonte
1

Sicuramente sceglierei la seconda opzione, basata sul principio KISS . Non c'è assolutamente alcun vantaggio nello spezzare, e quindi ritornare nella prossima istruzione.

Lo stesso principio si applica allo snippet seguente che vedo più spesso di quanto vorrei durante la revisione del codice:

if (somecondition)
     return true;
else
     return false;

Se non è presente alcuna registrazione o altro, basta sostituire lo snippet sopra con:

return somecondition;
    
risposta data 28.09.2016 - 11:06
fonte
-5

In entrambi i casi va bene. Personalmente, di solito non tornerei () nel mezzo del codice di una funzione. Piuttosto, di solito ho un blocco di codice alla fine di ogni funzione con l'etichetta "end_of_job:" che fa tutto il necessario per la manutenzione, fprintf () 's qualsiasi messaggio di debug (sotto una guardia), ecc. Anche se la tua funzione non al momento hai bisogno di tutto questo, potresti volerlo o averne bisogno in seguito. E forse il tuo ritorno (valore); cambierà a volte lungo la strada - non si vuole perdere la modifica di qualsiasi return in the middle (). Allo stesso modo, altre persone che mantengono il tuo codice non avranno l'opportunità di ignorare tali "hidden" return (). Invece, ovunque sia necessario return (), ho solo "goto end_of_job;" anziché. Ecco un esempio mocked-up ...

/* ---
 * end-of-job
 * ------------- */
end_of_job:
  /* --- eoj housekeeping --- */
  if ( temp_buffer != NULL ) free(temp_buffer);
  /* --- debugging --- */
  if ( msglevel>=99 && msgfp!=NULL ) {
    fprintf(msgfp,"func_name> this=%d, that=%f, etc\n",
    this,that,etc); fflush(msgfp); }
  /* --- back to caller --- */
  return(whatever);
} /* --- end-of-function func_name --- */
    
risposta data 28.09.2016 - 11:47
fonte

Leggi altre domande sui tag