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:
CPersonInstanzen:
CPerson PersonFunktionen:
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.
-
Kein Prefixe für Klassen. Also nicht
CFooBar
sondern einfachFooBar
(oder auchfooBar
oderfoo_bar
). -
Keine Prefixe für Typen. Also nicht
nSize
oderm_nSize
sondern einfachsize
undm_size
(odersize
undSize
oder ...). -
Kleine Ausnahme: für Interfaces wird oft noch der Prefix
I
verwendet, alsoIFooable
. 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 mitI
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 Prefixm_
+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ürenum
-Konstanten (C++03):EnumName_ValueName
Fürenum 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); } }