Thema: "Naming Conventions" (mein Tip!)



  • rapso schrieb:

    und wenn du eine neue member einbaust die du nutzen möchtest, prüfst du dann in der implementierungsdatei ob der variablenname schon in funktionen benutzt wurde und änderst den dort oder wie ist der workflow?

    Nein, aber da ich selten globale Variablen hab, krieg ich da kaum Konflikte.
    Lokale Variablen in Funktionen heissen bei mir oft gleich, die verlieren ja ihre gültigkeit beim Verassen des Blocks.

    void move( int x_, int y_, object& elem )
        elem.x = x_
        elem.y = y_
    }
    
    void check( int x_, int y_ object& elem )
        if( x_ == elem.x ) && ( y_ == elem.y ) {
            foo();
    }
    

    Gut ehrlich gesagt sind meine Projekte noch nicht so gross, so dass ich einigermassen im Kopf hab, wie was heisst, und sonst weiss ich wo ich nachschauen muss.
    Ausserdem hilft mir die alte Laboranten Regel: Alles eindeutig beschriften!



  • Also davon, die Datentypen als Kürzel hinzuzufügen, halte ich gar nichts. Wer den Code liest, sieht auch die Typdefinitionen - und dort steht wirklich drin, ob das nun eine int- oder long-Variable ist. Da ändere ich lieber einmal die Definition "int val;" nach "long val;", wenn mir die Genauigkeit nicht reicht, als jedes Vorkommen von "ival" in "lval" umzuwandeln (und am Ende erwische ich dann noch ein Vorkommen, das zu einer ganz anderen Variablen gehört).

    Was Sinn macht, sind logische Kennzeichnungen für die Variablen (z.B. ob dieser char* auf einen 0-terminierten String zeigt oder auf einen Bereich, der die Länge explizit mitführt) - sowas kann man nicht aus den reinen Deklarationen entnehmen, sondern benötigt Zusatzinformationen.



  • CStoll schrieb:

    Was Sinn macht, sind logische Kennzeichnungen für die Variablen (z.B. ob dieser char* auf einen 0-terminierten String zeigt oder auf einen Bereich, der die Länge explizit mitführt) - sowas kann man nicht aus den reinen Deklarationen entnehmen, sondern benötigt Zusatzinformationen.

    Hier lässt sich natürlich auch darüber streiten, ob man dafür dann nicht einfach nen eigenen Typ einführt, oder ein aussagekräftigeres typedef nimmt.



  • CStoll schrieb:

    Also davon, die Datentypen als Kürzel hinzuzufügen, halte ich gar nichts. Wer den Code liest, sieht auch die Typdefinitionen - und dort steht wirklich drin, ob das nun eine int- oder long-Variable ist. Da ändere ich lieber einmal die Definition "int val;" nach "long val;", wenn mir die Genauigkeit nicht reicht, als jedes Vorkommen von "ival" in "lval" umzuwandeln (und am Ende erwische ich dann noch ein Vorkommen, das zu einer ganz anderen Variablen gehört).

    für fälle bei denen man sich über den datentypen nicht sicher ist, sollte man einen typen per typedef deklarieren. es wäre sonst viel zu fehleranfällig nachträglich im source den typen zu ändern, da müßte man durch alle stellen an denen damit gearbeitet wird um dort sicherzustellen, dass auch dort der richtige typ angenommen wird. ein typedef ist da wesentlich sicherer, weil darauf der rest vom source auch aufbauen kann.

    CStoll schrieb:

    Was Sinn macht, sind logische Kennzeichnungen für die Variablen (z.B. ob dieser char* auf einen 0-terminierten String zeigt oder auf einen Bereich, der die Länge explizit mitführt) - sowas kann man nicht aus den reinen Deklarationen entnehmen, sondern benötigt Zusatzinformationen.

    auch dafür sollte man typenbezeichnungen nehmen, denn wenn deine var in anderen sourcen verwendet wird (mit accessor-function ausgelesen), ist garnicht mehr so sicher, dass dort die information ankommt die du im namen hattest. bei datentypen/typedefs sollte das weiterhin klar bleiben (sofern nicht jemand auf die "lustige" idee kommt es umzucasten, aber da kann man im debug templates/klassen drumrumbauen die kein casten erlauben).



  • 1310-Logik schrieb:

    Nein, aber da ich selten globale Variablen hab, krieg ich da kaum Konflikte.
    Lokale Variablen in Funktionen heissen bei mir oft gleich, die verlieren ja ihre gültigkeit beim Verassen des Blocks.

    void move( int x_, int y_, object& elem )
        elem.x = x_
        elem.y = y_
    }
    
    void check( int x_, int y_ object& elem )
        if( x_ == elem.x ) && ( y_ == elem.y ) {
            foo();
    }
    

    Gut ehrlich gesagt sind meine Projekte noch nicht so gross, so dass ich einigermassen im Kopf hab, wie was heisst, und sonst weiss ich wo ich nachschauen muss.
    Ausserdem hilft mir die alte Laboranten Regel: Alles eindeutig beschriften!

    ich sprech auch eher von membern in klassen, globale variablen nutzt man in c++ eigentlich garnicht mehr (ich hab jedenfalls keinen fall an dem ich das noch nutze), kann man zwar machen, aber kann man in klassen kapseln.
    in deinem source wären die _ eigentlich auch garnicht mehr nötig, weil du damit ja keine vars im scope "überschreibst" denk ich mir.



  • rapso schrieb:

    ich sprech auch eher von membern in klassen, globale variablen nutzt man in c++ eigentlich garnicht mehr (ich hab jedenfalls keinen fall an dem ich das noch nutze), kann man zwar machen, aber kann man in klassen kapseln.
    in deinem source wären die _ eigentlich auch garnicht mehr nötig, weil du damit ja keine vars im scope "überschreibst" denk ich mir.

    ach so, stimmt. ja bei members mach ichs genau so

    void rabbit::move( int x_, int y_ )
        x = x_;    // x und y sind Membervariable
        y = y_;
    }
    

    hier brauch ich den _
    na ja, den _ hab ich mir generell angewöhnt für temporäre variablen, (zB auch in if abfragen) , anstatt x_temp zu schreiben.
    das mit den globals ist schon klar, hab aber im moment noch einen mischcode wegen der SDL, die ich mal grob ausm tutorial übernommmen hab. werd die dann auch noch kapseln, aber erstmal muss ich wissen, wie der hase läuft 🙂



  • 1310-Logik schrieb:

    hier brauch ich den _
    na ja, den _ hab ich mir generell angewöhnt für temporäre variablen, (zB auch in if abfragen) , anstatt x_temp zu schreiben.
    das mit den globals ist schon klar, hab aber im moment noch einen mischcode wegen der SDL, die ich mal grob ausm tutorial übernommmen hab. werd die dann auch noch kapseln, aber erstmal muss ich wissen, wie der hase läuft 🙂

    ob du nun die localen grundsätzlich makierst, oder die member, am ende hast du die selbe differenzierung, die ich als nützlich ansprach 🙂



  • rapso schrieb:

    CStoll schrieb:

    Also davon, die Datentypen als Kürzel hinzuzufügen, halte ich gar nichts. Wer den Code liest, sieht auch die Typdefinitionen - und dort steht wirklich drin, ob das nun eine int- oder long-Variable ist. Da ändere ich lieber einmal die Definition "int val;" nach "long val;", wenn mir die Genauigkeit nicht reicht, als jedes Vorkommen von "ival" in "lval" umzuwandeln (und am Ende erwische ich dann noch ein Vorkommen, das zu einer ganz anderen Variablen gehört).

    für fälle bei denen man sich über den datentypen nicht sicher ist, sollte man einen typen per typedef deklarieren. es wäre sonst viel zu fehleranfällig nachträglich im source den typen zu ändern, da müßte man durch alle stellen an denen damit gearbeitet wird um dort sicherzustellen, dass auch dort der richtige typ angenommen wird. ein typedef ist da wesentlich sicherer, weil darauf der rest vom source auch aufbauen kann.

    Ich bin mir über den Typ ja sicher - ich brauche einen Ganzzahltyp. Und eine Unterscheidung zwischen "Ganzzahl-Variable" und "Gleitkomma-Variable" könnte ich noch verstehen, aber wenn man gesonderte Kürzel für int/long oder float/double einführt, ist das eher fehleranfällig als hilfreich

    CStoll schrieb:

    Was Sinn macht, sind logische Kennzeichnungen für die Variablen (z.B. ob dieser char* auf einen 0-terminierten String zeigt oder auf einen Bereich, der die Länge explizit mitführt) - sowas kann man nicht aus den reinen Deklarationen entnehmen, sondern benötigt Zusatzinformationen.

    auch dafür sollte man typenbezeichnungen nehmen, denn wenn deine var in anderen sourcen verwendet wird (mit accessor-function ausgelesen), ist garnicht mehr so sicher, dass dort die information ankommt die du im namen hattest. bei datentypen/typedefs sollte das weiterhin klar bleiben (sofern nicht jemand auf die "lustige" idee kommt es umzucasten, aber da kann man im debug templates/klassen drumrumbauen die kein casten erlauben).

    Ist dir schonmal aufgefallen, wie egal dem Compiler deine Namen sind? Oder daß typedef's in C++ nur eine besser klingende Alias-Bezeichnung definieren? Von daher sind solche Namenskonventionen nur für Menschen interessant, die meine Quelltexte lesen wollen. Und um alles eine Wrapperklasse drumherumzuschrauben, halte ich für Overkill (zumindest solange diese Klasse nicht mehr macht als meine internen Daten zwischenzulagern*).

    *Eine String-Klasse mit eigenen Verarbeitungsmethode ist durchaus sinnvoll. Eine String-Klasse, die nur einen char* verpackt und zur Unterscheidung zwischen C-String und Pascal-String eingeführt wurde, ist nur unnötiger Aufwand.



  • rapso schrieb:

    1310-Logik schrieb:

    hier brauch ich den _
    na ja, den _ hab ich mir generell angewöhnt für temporäre variablen, (zB auch in if abfragen) , anstatt x_temp zu schreiben.
    das mit den globals ist schon klar, hab aber im moment noch einen mischcode wegen der SDL, die ich mal grob ausm tutorial übernommmen hab. werd die dann auch noch kapseln, aber erstmal muss ich wissen, wie der hase läuft 🙂

    ob du nun die localen grundsätzlich makierst, oder die member, am ende hast du die selbe differenzierung, die ich als nützlich ansprach 🙂

    Genau, nur das ich bei Zugriffen wie rabbit.x nicht mehr tippe als nötig,
    während rabbit.m_uix 4 zeichen mehr sind :p



  • 1310-Logik schrieb:

    rapso schrieb:

    1310-Logik schrieb:

    hier brauch ich den _
    na ja, den _ hab ich mir generell angewöhnt für temporäre variablen, (zB auch in if abfragen) , anstatt x_temp zu schreiben.
    das mit den globals ist schon klar, hab aber im moment noch einen mischcode wegen der SDL, die ich mal grob ausm tutorial übernommmen hab. werd die dann auch noch kapseln, aber erstmal muss ich wissen, wie der hase läuft 🙂

    ob du nun die localen grundsätzlich makierst, oder die member, am ende hast du die selbe differenzierung, die ich als nützlich ansprach 🙂

    Genau, nur das ich bei Zugriffen wie rabbit.x nicht mehr tippe als nötig,
    während rabbit.m_uix 4 zeichen mehr sind :p

    bei:
    m_Size = Size;
    tippst du
    Size = Size_;
    ist das der große gewinn den du hast? *hehe*

    ich muss m[Shift]S[Tab] = S[Tab] tippen was sollte daran so aufwendig sein? 😉

    und wie ich schon sagte, ums tippen geht es nicht, das geht parallel zum denken und bedarf 0 aufwand meinerseits 😉



  • CStoll schrieb:

    ...Da ändere ich lieber einmal die Definition "int val;" nach "long val;"...

    Ich bin mir über den Typ ja sicher

    no offense, aber ich kann dir da nicht ganz folgen... wieso änderst du int zu long wenn du dir über den typen sicher warst, bzw widerspricht sich das nicht?



  • Als ich das Programm geschrieben habe, war ich mir noch sicher, daß int reichen sollte 😉 (und auch jetzt reicht ein kurzer Blick, um den korrekten Typ festzustellen). Und da ist es mir lieber, überhaupt keine Typkürzel im Namen zu haben als falsche.



  • rapso schrieb:

    und wie ich schon sagte, ums tippen geht es nicht, das geht parallel zum denken und bedarf 0 aufwand meinerseits 😉

    Nein, es geht um lesbarkeit. Der grosse Gewinn ist, dass ich Size im ersten überflug besser lesen kann, als m_uiSize.



  • 1310-Logik schrieb:

    rapso schrieb:

    und wie ich schon sagte, ums tippen geht es nicht, das geht parallel zum denken und bedarf 0 aufwand meinerseits 😉

    Nein, es geht um lesbarkeit. Der grosse Gewinn ist, dass ich Size im ersten überflug besser lesen kann, als m_uiSize.

    um die gegenbehauptung zu stellen: "man" kann besser m_Size lesen.

    am ende kommt es nur drauf an was "man" mehr gewohnt ist.



  • drum schrieb ich "ich" kann besser lesen 😉
    aber lassen wird das 🙂



  • 1310-Logik schrieb:

    warum nicht gleich so?

    //ctor
    Foo(unsigned int size_):
    size(size_)
    {
    }
    

    Den Paramter braucht man ja weniger oft als die Membervariable.

    Was aber vollkommen irrelevant ist. Member sind Internas und betreffen den Clienten nicht im geringsten. Leider denken Entwickler zu sehr selbstbezogen, da bist du auch keine Ausnahme. Benutze also entweder keine spezielle Benennung oder _nur_ bei den Membern. Ein Client sollte auf jeden Fall immer

    Foo(unsigned int size);
    

    sehen und nicht

    Foo(unsigned int size_);
    

    oder was auch immer.
    Und der evtl. Mehraufwand beim Schreiben ist schlichtweg zu vernachlässigen.



  • den client interessiert doch eh nur:

    Foo(unsigned int xxxx);
    

    weil er eh

    foo( any_specific_size );
    

    aufruft.
    da ist es doch egal, wie ich die variable intern nenne, oder?



  • Rufst Du lieber die Funktion

    f(int x, int xx, int xxx, int xxxx);
    oder die Funktion
    f(int x, int y, int width, int height);

    auf?

    Allerdings gehört der Variablenname nicht zur Funktionsdeklaration. Er kann also im Header und der Implementierung unterschiedlich heißen.



  • in c++ dürfte das eigentlich komplett egal sein und man könnte grundsätzlich nur noch mit structs arbeiten. aber der sauberkeit wegen arbeitet man mit klassen anders als mit structs. bei structs baut man keine funktionen ein und arbeitet dann auch direkt auf den daten, das würde man bei classen genau andersrum machen. wenn du nun ne struct übergeben bekommst und möchtest auf etwas zugreifen, dann greifst du halt direkt darauf zu. bei klassen würdest du erstmal eine accessor-function implementieren und über die zugreifen, falls sie noch nicht da ist.

    Du meinst bestimmt, dass man in C++ nur noch mit Klassen arbeiten kann.

    In einer OOP-Sprache spielt der Typ eines Objekts überhaupt keine Rolle, bzw der Typ interessiert nicht mehr. Das ist ja einer der Vorteile von OOP.

    Es spielt auch keine Rolle ob man mit einem Struct oder Klasse arbeitet. Entweder sind die Attribute Public, dann kann man sie direkt ändern, oder sie sind Privat, dann kann man die Attribute nur über Getter/Setter ändern.
    Der einzige Unterschied zwischen Struct und Class ist es, dass in einem Struct die Attribute standard public sind, wärend in Class sie standard privat sind. Ein Struct hat ebenso Contructoren und Methoden.

    Es spielt für den Benutzer auch keine Rolle ob ein Attribut Ganzzahl oder Realzahl ist. Entweder er kann dem Attribut eine Realzahl zuweisen oder er kann es nicht.
    Einem Attribut/Parameter wie size oder count würde man aber keine Realzahl zuweisen wollen.



  • wieso sollten sich IDE und prefixe unbedingt ausschliessen? nur weil man eine IDE hat, muss man doch nicht auf die vorteile einer styleguide verzichten.

    Redundanz. Hat sich die Informatik nicht der Verminderung von Redundanz wo es auch nur geht verschrieben?

    ich kann jetzt natürlich das argument bringen, dass nicht jede IDE gleich arbeitet und gerade diff-tools oft auf das highlighting von unterschieden spezialisiert sind, nicht auf syntax;)

    mit diff-tools Programmierst du ja nicht 🤡


Anmelden zum Antworten