Welche Notationen sind heute üblich?



  • Hallo,

    habe mich entschlossen mein Program von Grund auf neu zu schreiben. Beim alten Programm verwendete ich noch eine Notation, die vor 20 Jahren oft in Büchern zu finden war.

    Variablen mit Typkürzel:
    string sName;
    double dWert;
    int iZähler;
    usw...

    Membervariablen:
    m_sName;
    m_dWert;

    Klassennamen:
    CPerson

    Instanzen:
    CPerson Person

    Funktionen:
    void getName();
    void setWert();

    Welche Schreibweisen sind heute gebräuchlich / empfehlenswert? Wie werden z.B. Membervariablen zu lokalen Variablen unterschieden?



  • Ich persönlich arbeite eigentlich nur mit IDEs die genügend von der Sprache
    verstehen, um mir diese in den Namen eincodierten Informationen auf einen Blick
    zur Verfügung zu Stellen - entwender durch Syntax Highlighting (Typen, lokale,
    Member- und globale/statische Variablen haben eine jeweils andere Farbe) -
    oder indem ich mit dem Mauszeiger drüber fahre (Typ des Symbols und /oder
    Kontext in dem es deklariert wurde).

    Daher halte ich eigentlich nichts davon, diese Informationen zusätzlich in den
    Namen einzubetten, da das meines erachtens nur das "Rauschen" im Quellcode erhöht,
    und ihn schwieriger lesbar macht. bei mir sieht das also eher so aus:

    string name;
    double wert;
    int    zähler;
    
    class Person
    {
       public:
          string getName() const;
          int    getWert() const;
       private:
          string name;
          int    wert;
    }
    
    Person person;
    

    Ich empfinde diese schnörkellose Variante als gut lesbar und habe damit auch bei
    größeren Projekten noch keine Probleme gehabt. Lediglich wenn man sich mal schnell
    eine Datei in einem reinen Texteditor anschaut, muss man schonmal ein wenig suchen,
    damit man weiss um was es sich bei "name" handelt.

    Am Ende läuft es jedoch immer darauf hinaus was du persönlich oder dein Team in dem Umfeld, in dem entwickelt wird als sinnvoll erachten.
    Es gibt sicher für jede Notation gute Gründe - allerdings sollte man immer mal wieder hinterfragen, ob diese Gründe überhaupt noch relevant sind.
    Typ- und Member-Kürzel sind meiner Meinung nach dank moderner IDEs überholt.

    Finnegan



  • Das ist natürlich eine Frage auf die es nicht die Antwort geben kann.

    Ich kann dir aber schreiben von welchen Dingen ich den Eindruck habe dass sie zumindest sehr üblich sind.

    1. Kein Prefixe für Klassen. Also nicht CFooBar sondern einfach FooBar (oder auch fooBar oder foo_bar ).

    2. Keine Prefixe für Typen. Also nicht nSize oder m_nSize sondern einfach size und m_size (oder size und Size oder ...).

    3. Kleine Ausnahme: für Interfaces wird oft noch der Prefix I verwendet, also IFooable . Ist in C++ nicht so üblich, da es in C++ keine expliziten Interfaces gibt. (Man kann bloss Klassen machen die ausschliesslich auch virtual pure Membern ohne Implementierung bestehen -- diese kann man dann mit I prefixen. Sollte universell verstanden werden, auch wenn es vermutlich in den meisten Projekten nicht gemacht wird.)

    Was die restlichen Dinge angeht: da gibt es viele verschiedene Varianten.

    Ich persönlich verwende momentan...

    Für Klasse, Memberfunktionen und freie Funktionen: PascalCase
    Für Parameter und lokale Variablen: camelCase
    Für non-static Member den Prefix m_ + camelCase : m_camelCase
    Für static Member den Prefix: s_camelCase
    Für Konstanten mit static storage duration (static Member oder Namespace Member): PascalCase
    Für nicht konstante Variablen mit Namespace scope: g_camelCase
    Für Namespaces: PascalCase
    Für Makros alles Grossbuchstaben mit Underscore getrennt und dem Projektkürzel als Prefix: MYPROJ_MY_MACRO_NAME
    Für enum -Konstanten (C++03): EnumName_ValueName
    Für enum class -Konstanten (C++11): ValueName

    Was deinen Punkt "Instanzen" angeht: ich unterscheide nicht zwischen Instanzen von Klassen und Instanzen von eingebauten Typen ala int angeht. Alles was ich oben für Variablen, Parameter und Member geschrieben habe gilt also unabhängig davon ob es um einen eingebauten Typ geht oder userdefinierte Klassen.



  • Danke Finnegan und hustbaer für die ausführliche Darstellung und Erklärung eurer Notationen!

    Es ist ein gutes Argument, dass heutige IDE's ungarische Notation eigentlich überflüssig machen. Auf vorangestellte Kürzel weitgehend zu verzichten macht daher Sinn. Das werde ich dann auch tun.



  • Finnegan schrieb:

    Typ- und Member-Kürzel sind meiner Meinung nach dank moderner IDEs überholt.

    Die waren aber auch schon überholt als sie eingeführt wurden. Religiöser Quatsch.

    Kürzel, die Sinn haben könnten:

    pNode: p vor Pointern, um den * bei if(*p!=*e) nicht zu asvergessen. Der konsequente p nervt weniger als die flennenden kackboons am Schreibtisch.

    m_zahl: m_ vor Attributen, eigentlich nur in GUI-COde, wo es viele getter/setter gibt und man warumauchimmer nicht get/set vor getter/setter schreibt.

    globaleVariableSorryIchMachsiebaldweg_count: Globale Variablen sollten nicht aus Versehen so heißen können wie lokale.



  • Finnegan schrieb:

    string name;
    double wert;
    int    zähler;
    
    class Person
    {
       public:
          string getName() const;
          int    getWert() const;
       private:
          string name;
          int    wert;
    }
    
    Person person;
    

    Was soll das Untereinanderausrichten von Sachen, die keinen inhaltlichen Zusammenhang haben? Sowas finde ich total unfug (auch rQ).

    string      name      ;
    double      wert      ;
    int         zähler    ;
    class       Person    
    {
                public:     
                          string      getName   () const;
                          int         getWert   () const;
                private:    
                          string      name      ;
                          int         wert      ;
    };
    Person      person    ;
    

    Es sieht zwar irgendwie "hübscher" aus, aber verschlechtert die Lesbarkeit ein wenig und verschlechtert die Schreibbarkeit ein viel.



  • volkard schrieb:

    Was soll das Untereinanderausrichten von Sachen, die keinen inhaltlichen Zusammenhang haben? Sowas finde ich total unfug (auch rQ).

    Ist der Zusammenhang so schwer zu erkennen? Das sind die Namen der Member.
    Wenn ich mir die Klassendeklaration anschaue, sehe ich so auf einen Blick
    welche Member die Klasse hat und bei sinnvoller Namensgebung auch direkt
    was sie alles kann. Das hat halso mitnichten ästhetische Gründe, sondern
    hilft beim Lesen das was mich als erstes an dem Member interessiert schnell
    zu finden: seinen Namen.

    Du rückst doch sicher auch Blöcke ein, um schneller zu sehen wo sie beginnen,
    und wo sie aufhören - oder ist das auch religiöser Quatsch?

    Finnegan



  • Jo, ist alles                 Geschmachssache. 
    Mich stört es, wenn man       Sachen 
    auseinanderreißt, die         Vorteile
    entziehen sich mir.           Quatsch 
    eben. Hier mal ein kleiner    Test, 
    wieviel es im                 Deutschen 
    bringt, auf den ersten        Blick
    die sinntragenden             Hauptwörter 
    zu haben. Jo, hab den totalen Überblick! 
    Nee, nicht wirklich. Es macht Arbeit 
    und bringt gar nix. Mein      Arbeitgeber 
    hat für                       Cobol 
    nen                           Styleguide, 
    der statt ganz schlicht 4     Spaces
    zum                           Einrücken 
    zu nehmen                     Dutzende 
    von                           Regeln 
    und willkürlichen             Sonderfällen 
    birgt (umgebrochenes OR/AND 1 Space
    zum                           Beispiel, 
    sonst oft 4, aber erster      Tab
    bei                           Zeichen 
    20, zweiter bei 29). Die      Variablen
    wie "int zahl" lese ich als   Einheit. 
    Weder                         Name
    noch                          Typ
    allein bringen mir was.
    


  • Widerspruch            Dein Beispiel mit Deutschen Sprache trifft den Punkt leider nicht.
    
    Begründung             Ich reisse hier schliesslich keinen Code innerhalb einer Funktion willkürlich auseinander,
                           sondern lediglich Deklarationen von Klassenelementen, damit deren Name leichter auffindbar ist.
    
    Analogie zur           Ich sehe in einer Klassendeklaration auch so etwas wie einen Index, der mir dabei hilft,
    Deutschen Sprache      mir einen ersten Überblick über die Klasse zu verschaffen. Die Namen der Member würde ich also
                           eher mit Kapitelüberschriften vergleichen, als mit "sinntragenden Hauptwörtern" (wie for, if, return, etc).
                           Sie sind quasi eine Ultrakurzbeschreibung dessen, was der Wert repräsentiert, bzw. was die Funktion macht.
                           Er bescheibt die "Funktion des Elements".
    
    Mein Codeverständnis   Ich ziehe mein Codeverständnis hauptsächlich aus dieser Funtkion des Elements (also aus dem hoffentlich
                           gut gewählten Namen), und nicht aus seinem Typen oder sonstigen Attributen. Ob "Größe" es jetzt ein int,
                           float, int16_t oder sonstwas ist, ist ist für mich erstmal zweitranging, genau wie die Kapitelnummer oder
                           die Seite, wenn ich das Inhaltsverzeichnis eines Buches überfliege. Zuerst interessiert mich, dass der Wert
                           die Größe repräsentiert.
    
    Wo du Recht hast       Diese Schreibweise ist allerdings alles Geschmackssache, da gebe ich dir recht. Auch ich reiße ungern Dinge 
                           auseinander, daher wirst du sowas bei mir fast ausschließlich in Klassendeklarationen finden (und vielleicht
                           noch in den Doxygen-Kommentaren, wo die Funktionsparameter beschrieben werden).
    
    ~Epilog                Quatsch ist das, von dem man es nicht weiss warum man es macht (z.B. "weil es alle tun") oder was nachweislich
                           mehr schadet als nutzt... Und "religiösen Quatsch" möchte ich mir eigentlich nur vorwerfen lassen, wenn du mich
                           trollen willst. In diesem Fall: Gratulation zum Volltreffer :D. 
                           Gruss, Finnegan
    


  • Ja, volkard übertreibt wiedermal und bringt unpassende Vergleiche. Keine grosse Überraschung hier.

    Warum ich keine Ausrichtung ala Finnegan betreibe: weil sie durch einfache Refactorings ala "Rename" kaputt gemacht wird. Renamen tu' ich oft. Und dann überall durchgehen und alles wieder ausrichten... ne, sicher nicht.



  • Ich halte mich der Konsistenz wegen in C++ an die Namensgebung der Standardbibliothek: snake_case für alles. Was mir daran aber nicht gefällt ist, dass dann alles in demselben "Namensraum" ist und es ein bisschen schwieriger wird, Dinge auseinanderzuhalten.

    Was Formatierung und Klammerung angeht, kommt es auf den Kontext an. In der Regel setze ich auf die öffnende geschweifte Klammer für Typ- und Funktionsdefinition in ihre eigene Zeile und sonst (z.B. bei einer for Schleife) eher nicht. Allerdings schreibe ich es auch kompakter, der ganze Kram in eine Zeile passt. Und wenn ein Ausdruck zu lang ist, dann richte ich den Text meist ein bisschen aus, damit beim Lesen schneller klar wird, welche Klammern zusammen gehören. Zum Beispiel so:

    struct autodiff
    {
        double v;
        double d;
    
        autodiff(double v = 0.0, double d = 0.0)
        : v(v), d(d)
        {}
    };
    
    ad operator+(ad const& a, ad const& b)
    {
        return ad(a.v + b.v, a.d + b.d);
    }
    
    ad operator-(ad const& a, ad const& b)
    {
        return ad(a.v - b.v, a.d - b.d);
    }
    
    ad operator*(ad const& a, ad const& b)
    {
        return ad(a.v * b.v, a.v * b.d + b.v * a.d);
    }
    
    ad sin(ad const& x)
    {
        return ad(std::sin(x.v), std::cos(x.v) * x.d);
    }
    
    void foo()
    {
        for (int i = 0; i < 10; ++i) {
            langer_funktions_aufruf(dies, das, und_noch_mehr,
                                    und_noch_ein_parameter);
        }
    }
    

Anmelden zum Antworten