Qual è lo stile migliore per le funzioni con più ritorni e se / ultime istruzioni? [duplicare]

3

In una funzione in cui sono presenti più resi, qual è lo stile migliore da utilizzare?

Questo stile, dove non c'è "altro" perché è frivolo e pensi che sia più conciso?

f() {
    if (condition) {
        return value;
    }

    return other_value;
}

O questo, se pensi che 'else' fornisca un buon zucchero di sintassi per renderlo più leggibile?

f() {
    if (condition) {
        return value;
    } else {
        return other_value;
    }
}

Sentiti libero di condividere qualunque altra ragione tu possa avere per preferire uno rispetto all'altro.

EDIT:

I campioni di cui sopra sono ipotetici, se fossero così semplici, come notato da Yannis Rizos in basso, l'operatore ternario (valore di condizione: altro) sarebbe accettabile. Comunque sono interessato anche a casi come questo:

f() {
    if (condition1) {
        return value;
    } else if (condition2) {
        return value2;
    }
    ...
    else {
        return other_value;
    }
}
    
posta Thomas Dignan 27.12.2011 - 08:21
fonte

5 risposte

7

Preferisco questo :

return (condition) ? value : other_value;

ma è solo una questione di preferenze personali. In ogni squadra che ho lavorato sono stato felice di rispettare qualunque sia il documento di convenzione del codice preferito.

La "leggibilità" è un termine troppo vago da applicare in un problema così specifico e limitato e non esiste alcun motivo tecnico per preferire uno stile rispetto agli altri. Qualunque cosa tu ritenga sia più leggibile, ciò che conta di più è essere coerenti.

Questa domanda StackOverflow su Migliorare la leggibilità del codice offre alcuni punti importanti su altri aspetti, più importanti, di la leggibilità su cui dovresti concentrarti.

Ho capito che la domanda era ipotetica, ma la mia risposta è ancora valida. davvero non ha importanza .

Nell'esempio espanso, preferisco:

f() {
    if (condition1) {
        return value;
    } else if (condition2) {
        return value2;
    }
    ...

    return other_value;
}

Ma per una ragione molto specifica: organizzo i blocchi in modo tale che l'ultimo, il return other_value; è quello che è più probabile che accada, quindi il mio codice allude alla logica del business - e non sto fingendo è intelligente Ancora una preferenza strettamente personale, l'unica ragione dietro di esso è il mio personale processo di organizzazione del codice, che eviterei felicemente se andasse contro le convenzioni della squadra.

In ogni caso, se hai più di un paio di blocchi consecutivi di else if , la riscrittura in una istruzione switch probabilmente ha più senso, in termini di leggibilità.

    
risposta data 27.12.2011 - 08:28
fonte
6

Naturalmente, come altri hanno sottolineato, è principalmente una questione di preferenze personali. La parola chiave qui è principalmente . Vi sono, tuttavia, alcune linee guida obiettive che possono essere utilizzate, e personalmente, mi piace formulare le mie preferenze personali sulla base di linee guida oggettive, indipendentemente da quanto insignificanti possano essere queste.

Quindi, il modo in cui lo faccio è il seguente:

if( condition )
    return;
do-other-stuff;

E codifico sempre le istruzioni multiple-if-else come segue:

if( a ) return x;
if( b ) return y;
if( c ) return z;
return null; //whatever, I ran out of letters

Ed ecco perché:

In profondità a livello di linguaggio assembly, la parola chiave 'else' corrisponde ad un codice. Un'istruzione if-then-else nel linguaggio assembly ha questo aspetto:

    test condition
    if false, jump to else
    perform the if-part
    jump to end
else:
    perform the else-part
end:

L'istruzione 'jump to end' può essere pensata come il codice a cui corrisponde la parte 'else'. Ora, considera come il frammento di codice sopra riportato cambi quando l'if-part è un'istruzione return:

    test condition
    if false, jump to else
    do-some-stuff-and-return
    jump to end
else:
    perform the else-part
end:

Chiaramente, l'istruzione 'saltare alla fine' non verrà mai eseguita. Sarei disposto a scommettere che quando un compilatore analizza il tuo codice per trovare il codice irraggiungibile, capisce che la parola chiave 'else' è irraggiungibile, e lo tiene in considerazione, ma si astiene dall'emettere un avvertimento perché questo stile è usato da molti là fuori, e non vuole turbarli. Ma io uso questo come una giustificazione obiettiva, non importa quanto sia insignificante, per non usare mai la parola chiave 'else' quando restituisce la parte if.

    
risposta data 27.12.2011 - 09:26
fonte
3

Mi piace quello che ha scritto lo zio Bob in Pulisci codice . È stato qualcosa del genere quando scrivete codice pulito e leggibile, le vostre funzioni dovrebbero essere abbastanza piccole (e ovviamente in una singola pagina) che non dovreste aver bisogno di questo tipo di linee guida o di specifiche di stile.

Invece il tuo obiettivo numero 1 è migliorare la leggibilità il più possibile. Finché è leggibile e chiaro, qualsiasi altra cosa è solo una preferenza personale. Suppongo che l'esempio che hai fornito fosse solo un esempio ipotetico, ma se fosse un codice reale, allora Yannis ti ha dato sicuramente un'alternativa più leggibile.

    
risposta data 27.12.2011 - 08:33
fonte
2

La mia preferenza personale è includere il else non necessario. Trovo di poter gettare il flusso di controllo a colpo d'occhio quando è lì, rispetto a dover ricordare di cercare return s che diramano il flusso implicitamente. Un paio di volte sono tornato a codice a freddo e ho aggiunto qualcosa dopo un "se" e sono stato confuso sul motivo per cui non era in esecuzione, solo per rendermi conto che non avevo visto il ritorno che ha salvato la funzione prima di arrivare al mio nuovo materiale .

    
risposta data 27.12.2011 - 15:07
fonte
1

Il "pattern var singolo" spesso trovato in Javascript suggerisce singoli punti di ritorno insistendo sul fatto che tutte le variabili sono dichiarate nella parte superiore del corpo della funzione per impedire "sollevamento". Quindi, registrare le valutazioni invece di ritornare può impedire la necessità di un ELSE (che ho una strana avversione per ...):

 function doThis(required){
    var result = false;
    if(required){
        //base implementation
        result = doThat();
    }
    return result;
 }

Se hai condizioni sequenziali o opzionali e non riesci ad accedere a un'altra funzione, puoi farlo:

 function doThis(required, opt){
    var result = false,
        oRequirement = 'foo';
    if(required){
        //base implementation
        result = doThat();
        if(result !== false && opt !== undefined && opt === oRequirement){
                //optional implementations
                result = doOptional();
            } else {
                //undo previous truthiness
                result = false;
            }
        }
    }
    return result;
 }

È possibile delegare il consumo di variabili esternamente, rendendo questa funzione effettivamente una "clausola di salvaguardia":

 function vA(a){
     return true;
 }

 function vB(c){
     return true;
 }

 function vB(c){
     return true;
 }

 function doThis(required, opt){
    var result = false;
    if(vA(required)){
        //base implementation
        result = doThat(required);
        if(vB(result) && vC(opt)){
            //optional
            result = doOptional(opt);
        }else{
            result = false;    
        }
    }
    return result;
 }

Potresti suddividere le tue valutazioni:

 function doThis(required, opt){
    var result = false;
    if(if(vA(required)){
      //base
      result = doThat(required);
    }

    if(if(vB(result) && vC(opt)){
      //optional
      result = doOptional(opt);
    }
    return result;
 }

Le ternarie possono ridurre le dimensioni e sono molto carine, ma possono essere un po 'più difficili da eseguire il debug e un po' scomode se si ha bisogno di molte fasi di valutazione annidate:

function doThis(a, b, c){
    var o = false;
    if(valid(a)){ //assuming some sort of validation is required
        if(b !== undefined && valid(b)){
            o = c ? //an optional step
                doMore(a) ?
                    new Foo(a, b) :
                    false :
                new Bar(b, a) ;
        }
    }
    return o;
}

In generale, ho bisogno di annidare le istruzioni IF se sono presenti argomenti facoltativi . Quando il risultato è il risultato di un processo all'interno del corpo, suggerisce di delegare o concatenare in un metodo separato.

Detto questo, non posso fare a meno di pensare che non c'è un modo "giusto" (anche se ci sono sicuramente quelli sbagliati ...), ed è questo fatto che rende la codifica una professione creativa capace di una vasta gamma di espressione. Voglio dire, chi non ama un po 'di refactoring?

    
risposta data 28.12.2011 - 00:11
fonte

Leggi altre domande sui tag