was ist besserer Stil !?!?



  • Ich würde wohl ersteres verwenden (aber bitte keine leere return-Anweisung in einer long-Funktion ;)). Aber ich fürchte, das hier könnte zu einem Galubenskrieg ausarten.



  • Wie sagt man so schön "halt den Ball flach". Dasselbe gilt auch für Funktionen, daher präferiere ich ebenfalls die erste Methode. Dank RAII hat man auch keine Probleme mit dem Aufräumen.



  • Ich würde die erste Methode bevorzugen (wenn das retun statement noch korrekt wäre :p). Aus den schon genannten Gründen: Man sieht sofort, was passiert und die Einrückungsebene wird nicht so tief.



  • sorry fuer das leere return. compiler haette es sowieso nicht gefressen .. es war natuerlich ...

    return 0
    

    ... gemeint
    ich ziehe auch erstere variante vor. aber bei mir am arbeitsplatz gibt es ein paar herren, die das fruehe ermitteln von ausstiegskriterien und dann ein unmittelbares return nicht so schoen finden.
    ich glaubte mich irgendwo zu erinnern, dass ich sowas mal gelesen habe dass variante 1. besser ist.
    Wer einen hinweis hierauf (auf obige problematik des stils) weiss, bitte link oder url schicken.

    vielen dank.
    gruss.



  • CStoll schrieb:

    Aber ich fürchte, das hier könnte zu einem Galubenskrieg ausarten.

    In der Tat, wobei ich denke die Notwendigkeit für Methode 2 ist dank RAII nicht mehr gegeben. Notorische goto-Meider hatten vorher quasi keine andere Wahl (mal abgesehen von der Aufspaltung in Mikrofunktionen) 😃

    int ret = OK;
    FILE* f = fopen(...);
    if (f) {
        Struk* s = read_and_create(f);
        if (s) {
            ....
            free(s); // <-- (2)
        } else
            ret = FEHLER;
        fclose(f); // <-- (1)
    } else
        ret = FEHLER;
    
    return ret;
    

    vs.

    fstream f(...);
    if (!f) return FEHLER;
    
    auto_ptr< Struk > s( new Struk );
    if (!s->read(f)) return FEHLER;
    
    return OK;
    // <-- (1) und (2), falls jemals erzeugt
    


  • ersteres ist besserer stil, da es den code leichter verständlich macht.

    sobald man irgendwo, an irgendeiner stelle, ein return sieht, dann kann man sich 100% sicher sein, dass die aktuelle methode mit dem wert verlassen wird, der an der stelle steht.

    sonst man sich erstmal durch einen wust an if/else oder womöglich noch diverse gotos quälen muss, bis man feststellt, was der ganze krempel soll.

    man sollte als faustformel weiterhin im kopf behalten: mehr als drei tabs einrückungstiefe sind meist schon zuviel spaghettierung und ab fünf tabs sollte man den code einstampfen 😉



  • @LordJaxom: Beim ersten Codebeispiel wird die Datei gar nicht geschlossen, wenn read_and_create() einen ungueltigen Pointer zurueckliefert.



  • DEvent schrieb:

    @LordJaxom: Beim ersten Codebeispiel wird die Datei gar nicht geschlossen, wenn read_and_create() einen ungueltigen Pointer zurueckliefert.

    Hast recht, ich arbeite schon zu lange nicht mehr mit C. Da könnte man dann einer Returnvariablen in den else-Zweigen Fehlercodes zuweisen und das Return als letzte Anweisung plazieren. Aber das Beispiel ändere ich jetzt nicht mehr ab, ich denke der Sinn ist klar 😉

    EDIT: Doch noch geändert



  • weiss keiner hier ein nachschlagewerk (url oder link) in welchem programmierstil mit obiger problematik besprochen und dargestellt wird!?!?

    vielen dank.



  • Entweder die 1. Variante, oder so:

    long foo(long pSomeLong)
    {
        return Bedingung(pSomeLong) ? 0 : foo2(pSomeLong);
    }
    
    long foo2(long pSomeLong) 
    {
        // ggf. das assert weglassen, kommt drauf an was der Code eigentlich macht, und ob
        // "!Bedingung(pSomeLong)" eine "precondition" für den folgenden Code ist
        assert(!Bedingung(pSomeLong));
    
        DoBerechnung(pSomeLong);
        DoThis();
        DoThat();
        MaybeThisToo();
        return CalcResult(pSomeLong);
    }
    

    EDIT: BTW: diese prefixes ("p") sind ganz ekelig, und "p" verwendet man normalerweise für Zeiger, und nicht für Parameter.



  • würd dann aber nen aussagekräftigeren bezeichner wählen. fooImpl oder so



  • thordk schrieb:

    würd dann aber nen aussagekräftigeren bezeichner wählen. fooImpl oder so

    ja, sehr aussagekräftig 😃



  • na besser als foo2 😃

    long foo(long someLong)
    {
      if(Bedingung(someLong))
       return fooImpl(someLong);
      return 0;
    }
    
    long fooImpl(long someLong)
    {
      ...
    }
    

    abgesehen vom bezeichner hat diese methode den vorteil, dass man eine funktion schreiben kann, die garantiert mit einem "korrekten" wert aufgerufen wird. macht das ganze übersichtlicher.



  • Ich habe letztens irgendwo (= vermutlich in einem Python-Buch/Internetseite/oder Forum) gelesen: "Exit as soon as possible"

    Alleine vom Codeverständnis ist es mir angenehmer eine Funktion (oder einen Block) dann zu verlassen, wenn es möglich/nötig ist.

    Vom Laufzeitverhalten dürften sich beide Varianten nicht viel tun (wenn ich mal so an meine "Assembler-Zeit" zurückdenke). Um ein CMP und ein JE, JNE (x86) etc. kommt man ja ohnehin nicht herum.



  • Die 2. Variante kommt von Sprachen wie C. Wenn man nur einen Eintritt- und einen Austrittspunkt hat, hat man genau definierte Punkte an denen man Ressource de/allokieren kann. In C++ ist das ganze wegen Exceptions hinfällig. Jede Codezeile ist jetzt ein möglicher Austrittspunkt und damit die Objekte per RAII zu schützen. Da das Konzept also nicht paßt und die erste Variante übersichtlicher ist nehme ich diese.



  • Hm. Auf der einen Seite find ich persoenlich die erste Variante uebersichtlicher -wenn nix zu tun ist gleich return. Andererseits hab ich vor kurzer Zeit irgendwo eine Richtlinie a la "avoid multiple return statements" gesehen, ausgegeben von Herb Sutter. Da wuerde das so aussehen:

    long foo(long pSomeLong)
    {
      long ret = 0;
      if(!Bedingung( pSomeLong ) )
      {
       DoBerechnung( pSomeLong );
       DoThis();
       DoThat();
       MaybeThisToo();
       ret = CalcResult( pSomeLong );
      }
    
      return ret;
    }
    

    /edit: hab mich halbwegs vertan, er hat diese Regel zwar mal aufgestellt, sie aber wohl wieder verworfen: http://www.gotw.ca/gotw/002.htm Punkt 5.


Anmelden zum Antworten