C++ Gurus
-
Ich kann Dein Problem an der ganzen Sache nicht wirklich verstehen. Aber wir werden uns hier glaube ich eh ständig im Kreis drehen, ohne uns wirklich einigen zu können, glaube ich.
Bei Klassen und Funktionen wählt man recht aussagekräftige Bezeichner, soweit ich weiß auch in erster Linie in der Schnittstelle, alles, was klassenintern ist, ist wieder so eine andere Geschichte.
Das "T" in den Templates ist ja nur ein Platzhalter für "irgendwas", wenn ich eine Templatefunktion habe, dann habe z.B.
template<typename R, typename T, typename X>R TuWas(T Key, X Value) { ... }
Den Typen bestimme ich, wenn ich das Template aufrufe, und die IDE zeigt mir die Namen der Parameter an, also weiß ich doch trotzdem, welcher Parameter an welcher Stelle wofür steht. Wenn ich
template<typename ReturnType, typename KeyType, typename ValueType>ReturnType TuWas(KeyType Key, ValueType Value) { ... }
habe, dann halte ich das irgendwie für doppelt gemoppelt. Warum soll ich da unbedingt "ValueType" angeben, wenn es doch durch den Bezeichner klar ist, dass da der Typ des "Values" angegeben wird?
Zu der i1-Geschichte: Meine PHP-Sources sind voll von Schleifen, wo ich $i1, $i2, etc. verwende. $i1 für die äußerste Schleife, usw. So kann ich jederzeit jede Laufvariable zuweisen. Bei i, j, k, l würde mir dies schwerer fallen.
-
Shade Of Mine schrieb:
Niemand würde ernsthaft eine Klasse I1 nennen oder eine Variable i1 - aber sobald wir bei Templates sind gehört das zum guten Ton?
'Warum' frage ich. Alles was ich als antwort bekomme ist "kann man doch eh lesen" - aber was ist so schlecht an lesbaren Bezeichnern? Warum nur bei Templates? Was hindert einem daran die paar Zeichen mehr zu schreiben?Auch bei Templates nennst du ja nicht die Klasse T oder sonstwas sondern nur die Templateparameter.
'Von Außen' ist da nirgends etwas einbuchstabiges zu sehen, nur innerhalb des Templates; dort sollte dann auch leicht ersichtlich wofür es steht (falls es sich nicht ohnehin um eine Lib handelt wo lediglich die Doku ausschlaggebend ist/sein sollte.)Das ganze zählt natürlich nur für - im weitesten Sinne - Container-of-T, super-generische Algos oder sonstige 'klare Fälle' (
). Ansonsten zählt natürlich, wie schon zuvor angemerkt und auch nie anders in meinen Beispielcodes zu finden, sinnvolle Bezeichner zu finden und schlicht ein (Konvention) T oder Type anzuhängen, sofern die Natur des Bezeichners (z.B. "fooPolicy") ersichtlich ist.
-
Es gibt kein aussen und innen.
Es ist alles der Code den man warten muss.Nur weil eine Methode private ist, nennen wir sie doch nicht p1 wenn ein stripInvalidSymbols() viel passender wäre, oder?
Wie nennen wir denn unsere Member Variablen?
m1, m2?
Nein, wir nennen sie value, size, speed, fuel,...Natürlich ist der Template-Type ein Platzhalter für 'etwas'. Aber dieses 'etwas' hat ja bestimmte Beschränkungen oder einen bestimmten Nutzen/Verwendungszweck.
Vergleich mal meine 2 copys. Welches ist leichter lesbar?
Das mit dem ValueType ist wie volkard schon gesagt hat, suboptimal. Viel besser ist ein
template<typename Result, typename Key, typename Value> Result tuWas(Key key, Value value) { ... }
Denn damit ist sofort klar was tuWas nun liefert. Nämlich Result. Ein R? was wäre R? Hat das R innerhalb der Funktion eine bestimmte Rolle? Ist es nur Result oder etwas Reziprokes? Reversal? Refund? Repeat? Restrict?
Tut es weh die paar Buchstaben zu schreiben?
Nehmen wir eine beliebige Funktion (ohne Templates)
R f(A a)
cool, was macht die denn? Keine Ahnung.
jetzt mit Templates:template<typename R, typename A> R f(A a)
jetzt ist alles klar, stimmts?
Wie man erkennt, ändert sich die Bedeutung ob mit oder ohne Templates nicht. Ein Typ A sagt mir nix. ein Product, Factor, LoopCondition oder was auch immer hilft mir aber den Sinn sofot zu verstehen.
Nehmen wir nochmal das schöne copy Beispiel (dass ihr so gerne ignoriert):
template<typename A, typename B> A copy(B b1, B b2, A a);
das ist eure Methode: kurze Bezeichner, weil es ja eh klar ist was sie machen.
Ich behaupte aber
template<typename InIter, typename OutIter> InIter copy(OutIter start, OutIter end, InIter target);
ist besser lesbar.
Natürlich kann A nahezu jeder Typ sein, aber lustigerweise macht es nur mit einem Iterator-Typ Sinn.
Oder nehmen wir
template<typename T, class A, class C> class Stack {};
Alles klar?
Nein?
Wie wäre es mit:template<typename Type, class Allocator, class ContainerImpl> class Stack {};
jetzt _ist_ es klar.
Bei Schleifen: i, j, k, l sind (wie ich schon so oft gesagt habe) standardisierte Namen in einem engen eingeschränkten Kontext. Ein i muss immer zu einer Zählschleife gehören. Ein T muss aber nur ein Typ sein. Das ist doch etwas vage... Zumal A und C auch Typen sind, aber welche Rolle spielen sie? Keine Ahnung.
Bei i und j weiss ich es: ich habe 2 Schleifen: i ist die äußere j die innere. Ich würde zwar nie i1, i2, i3 dafür verwenden, aber das mag auch ok sein. Wichtig ist: ich sehe den Namen und weiss welche Rolle er spielt. Das ist bei T aber _unmöglich_.Man lehrt dass sogar den Anfängern: jeder Bezeichner soll so aussagekräftig wie möglich sein. Lieber ein Wort zuviel als zu wenig. Das ist gut so, weil man den Code dadurch leichter lesen kann.
ein
template<typename A, typename B, typename C>
zu lesen ist dagegen schwer.Nochmal meine Frage:
was kostet es, den Bezeichner einen ordentlichen Namen zu geben? Wir machen es doch überall anders auch so, oder? Warum hier nicht?'Weil es unnötig ist' ist eine doofe Begründung. Denn es ist auch unnötig lokalen Variablen vernünftige Namen zu geben, ein char b[100] reicht doch statt einem char buffer[100] oder ein S s; statt einem string str; Wozu überhaupt lange Namen verwenden?
S ist string, also typedef std::string S; V ist vector (dass es auch Value oder Variadic oder Variant etc. heissen kann ignorieren wir natürlich)Dann sehen unsere Codes so aus:
V<C> v; v.p('a'); v.p('b'); v.p('c'); S s(v.b(), v.e()); c<<s;
geil!
-
mantiz schrieb:
template<typename R, typename T, typename X>R TuWas(T Key, X Value) { ... }
template<typename ReturnType, typename KeyType, typename ValueType>ReturnType TuWas(KeyType Key, ValueType Value) { ... }
Also ich als Anfänger finde die 2. Version wesentlich besser lesbar. Ich hab mir auch selbstprechende Namen (möglichst ohne Ungarische Notation) angewöhnt. Ich finde es manchmal sogar schwieriger die Passenden Namen für Variablen und Funktionen, für ein bestimmtes Problem oder eine bestimmte Klasse, zu finden als das eigentliche Problem zu lösen. Allerdings lohnt sich das (bei mir) auch immer da ich auf diese Weise Komplexere Algorithmen wirklich besser lesen kann. Es ist einach nur schön nicht die Maus über eine Variable halten zu müssen um den Variablentyp zu sehen. Hab mir auch schon so tolle (aber meiner Meinung nach Aussagekräfige) Namen wie:
int GroesseDesCStringsInByte; //irgendein Kommentar der kurz die Verwendung erklärt int ZeilenAnzahl;
einfallen lassen. Naja mir hats bisher immer geholfen die Lösung meines Problems "passiv" zu erklären. Das mach ich übrigens auch bei kleinen, lästigen und kurzen Funktionen.
PS: weis einer von euch überhaupt noch worum es in desem Thread geht? OHNE nochmal den ersten Beitrag zu lesen?
-
@Chris++:
Meine Variante wäre hier:int Length; // in Bytes; Verwendung int RowCount;
dürfte nicht weiter zu Missverständnissen führen, da man die Variablen ja sowieso in einem möglichst kleinen Kontext/Block definiert, wo man sie braucht. Englische Bezeichner sind häufig kürzer, als deutsche und genauso aussagekräftig, finde ich.
Ein Beispiel evtl. noch, wenn ich eine Funktion MoveResized beispielsweise habe, dann würde ich die so definieren:
void MoveResized(int x, int y, int w, int h);
Man könnte auch:
void MoveResized(int Left, int Top, int Width, int Height);
nehmen, was aber meiner Meinung nach überhaupt keinen Vorteil bringt. Man weiß, dass x und y die obere linke Ecke angeben, und im Kontext vom in der Größe verändernden verschieben sollte es auch klar sein, wofür w und h stehen. Wenn ich diese Funktion in der WinAPI für Fenster implementiere, dann rufe ich genau eine Funktion mit diesen Parametern auf:
void MoveResized(int x, int y, int w, int h) { ::MoveWindow(x, y, w, h, true); }
Wofür ausschreiben, ist doch klar, was da passiert?
In diesem Beispiel wäre Top evtl. sogar schon fast grob fahrlässig, denn man könnte ja evtl. auch das Koordinatensystem ändern, wo x und y auf einmal die untere linke Ecke angeben und schon stimmen die schönen selbsterklärenden Bezeichner nicht mehr.
@copy-Beispiel:
Wenn nur ein Iterator Sinn macht, geht dann nicht sowas in der Art?template<typename T1, typename T2> vector<T1>::iterator copy(vector<T2>::iterator itStart, vector<T2>::iterator itEnd, vector<T1>::iterator itTarget);
Bin mir nicht sicher, ob das so funktioniert, aber von der Art her sollte klar sein, was ich meine.
Vectoren, Maps, etc. müssten u.U. sowieso unterschiedlich behandelt werden und so hätte man eine gewisse Typsicherheit, denke ich, oder?
-
Chris++ schrieb:
Ich finde es manchmal sogar schwieriger die Passenden Namen für Variablen und Funktionen, für ein bestimmtes Problem oder eine bestimmte Klasse, zu finden als das eigentliche Problem zu lösen.
Dann bist schon ziemlich weit. Denn normalerweise erreichen die meisten Leute die Hürde garnicht...
Ich verwende auch oft 30% der Zeit für Namensfindung. Manchmal sogar mehr. Es zahlt sich einfach aus - wenn ich an meine Zeit an dt2 denke -> urghs, data_save, data_session_save, data_read und die meiste Zeit wurde nix ge'read'et oder ge'save'et...
-
Seit ich bei der Ferialarbeit letztes Jahr mit einem sehr großem Softwareprojekt zu tun hatte sehe ich ein das sich solche Arbeit auszahlt. Ich konnte es sehr lange nicht glauben warum man für jede Methode einen JavaDoc-Kommentar schreiben soll. Jetzt weiß ich es. 2000 Quellcodedateien lassen nicht nur leicht sondern äußerst leicht den Überblick verlieren. Und eine Klasse ohne Doku steht da ganz schnell ohne Benutzer da, weil der Autor die Firma irgendwann verlassen hat.
Auch wird sehr viel Aufwand für JUnit-Tests aufgewendet - auch ein Ding der Unvorstellbarkeit - bei mir vor einigen Jahren.
@mantiz: Top, Left sind gute Variablennamen - allerdings nur wenn sie mit kleinem Anfangsbuchstaben beginnen
template<typename T1, typename T2> vector<T1>::iterator copy(vector<T2>::iterator itStart, vector<T2>::iterator itEnd, vector<T1>::iterator itTarget);
Solch Code schockt mich immer, da verspüre ich zuerst den Drang nach einem typedef, danach den Drang nach einer anderen Programmiersprache. Also wenn sich in C++ was ändern soll dann Templates.
MfG SideWinder
-
mantiz schrieb:
void MoveResized(int x, int y, int w, int h) { ::MoveWindow(x, y, w, h, true); }
Wofür ausschreiben, ist doch klar, was da passiert?
Nein, ich weiss nicht das da passiert. Was macht das true?
Aber deshalb gibt es ja die geniale Erfindung von structs
void moveResized(Rectangle rect) { ::MoveWindow(rect.x, rect.y, rect.width, rect.height); }
Viel schöner. Zumal man die Werte alle zusammen speichern kann, denn einer alleine ist hier ja sinnlos.
Aber du lenkst die ganze Zeit vom Thema ab. Das finde ich langweilig. Ich schreibe da wirklich viel, erkläre die Sachen möglichst einfach und du ignorierst es einfach... Das ist nicht lustig
In diesem Beispiel wäre Top evtl. sogar schon fast grob fahrlässig, denn man könnte ja evtl. auch das Koordinatensystem ändern, wo x und y auf einmal die untere linke Ecke angeben und schon stimmen die schönen selbsterklärenden Bezeichner nicht mehr.
Niemand will die X Koordinate Top nennen, das ist blödsinn. x bleibt x, y bleibt y, width bleibt width und height bleibt height.
@copy-Beispiel:
Wenn nur ein Iterator Sinn macht, geht dann nicht sowas in der Art?template<typename T1, typename T2> vector<T1>::iterator copy(vector<T2>::iterator itStart, vector<T2>::iterator itEnd, vector<T1>::iterator itTarget);
Bin mir nicht sicher, ob das so funktioniert, aber von der Art her sollte klar sein, was ich meine.
Ne, was soll das denn sein? Ungarisch auch noch mit rein und effektiv templates/iteatoren aushebeln?
Vectoren, Maps, etc. müssten u.U. sowieso unterschiedlich behandelt werden und so hätte man eine gewisse Typsicherheit, denke ich, oder?
Nein, ich werde jetzt keine Grundsatzdiskussion über Templates anfangen. Sorry. Dein copy macht keinen sinn, du hebelst damit das iterator konzept aus.
-
mantiz schrieb:
@Chris++:
Meine Variante wäre hier:int Length; // in Bytes; Verwendung int RowCount;
dürfte nicht weiter zu Missverständnissen führen, da man die Variablen ja sowieso in einem möglichst kleinen Kontext/Block definiert, wo man sie braucht. Englische Bezeichner sind häufig kürzer, als deutsche und genauso aussagekräftig, finde ich.
Ist auch eine Möglichkeit aber manchmal auch Kontext- / Problemabhängig. Ich lese in meinem Programm z.B. vorher verschiedene Längen aus. Einmal die Länge einer Datei, dann wieder die länger von irgendwas anderes und zu guter letzt die Länge des CStrings. Da dies alles im selben Kontext steht, reich ein einfaches Length nicht mehr. Ausserdem bin ich kein Freund von Englischen Bezeichnungen. Ok sie sind kürzer, hier und da Aussagekräftiger aber es gibt auch Ausnahmen wo ein Englisches Wort viele Bedeutungen haben kann. Ausserdem ist es Geschmacksache (vor allem da mir manche Englische Bezeichnungen einfach nichts sagen und ich keine Lust hab irgendwo nachzulesen, das nervt dann auf dauer).
Shade Of Mine schrieb:
Chris++ schrieb:
Ich finde es manchmal sogar schwieriger die Passenden Namen für Variablen und Funktionen, für ein bestimmtes Problem oder eine bestimmte Klasse, zu finden als das eigentliche Problem zu lösen.
Dann bist schon ziemlich weit. Denn normalerweise erreichen die meisten Leute die Hürde garnicht...
Ich verwende auch oft 30% der Zeit für Namensfindung. Manchmal sogar mehr. Es zahlt sich einfach aus - wenn ich an meine Zeit an dt2 denke -> urghs, data_save, data_session_save, data_read und die meiste Zeit wurde nix ge'read'et oder ge'save'et...
Ok ich denke das meine Probleme noch nicht so extrem schwierig sind. Aber es gibt ja Teilprobleme einer Aufgabenstellung die besonders viel Hirnschmalz brauchen (je nach Erfahrung und Schwierigkeit)... Und bei einem längeren Algorithmus vergesse ich auch gerne mal was ich vor 2 Stunden geschrieben hab (und vor allem warum). Da ist es ganz praktisch wenn man sich schnell wieder reinfinden kann.
-
Shade Of Mine schrieb:
Was macht das true?
Dafür bin ja dann nicht ich zuständig, sondern der Entwickler der Funktion MoveWindow. Wobei hier im Header soweit ich weiß sogar steht: bRepaint, was die IDE ja dann auch anzeigen sollte, also ist alles klar.
Shade Of Mine schrieb:
Aber deshalb gibt es ja die geniale Erfindung von structs
void moveResized(Rectangle rect) { ::MoveWindow(rect.x, rect.y, rect.width, rect.height); }
Viel schöner. Zumal man die Werte alle zusammen speichern kann, denn einer alleine ist hier ja sinnlos.
Könnte man so machen, aber entweder läuft das dann auf sowas hinaus:
Rectangle rect(100, 100, 200, 200); // oder schlimmer ohne ctor und einzeln zuweisen moveResized(rect); // oder sofort so: moveResized(Rectangle(100, 100, 200, 200));
wobei das hier aber eher unnötig ist ein tmp-Objekt zu erzeugen, denke ich. Zum Speichern kann man die Werte ja dann ruhig in ein struct packen.
Shade Of Mine schrieb:
Niemand will die X Koordinate Top nennen, das ist blödsinn. x bleibt x, y bleibt y, width bleibt width und height bleibt height.
Dann ist ja gut.
War ja auch wieder nur ein Beispiel.
Shade Of Mine schrieb:
Ne, was soll das denn sein? Ungarisch auch noch mit rein und effektiv templates/iteatoren aushebeln?
Dann lass das "it" davor weg.
Wenn nur iteratoren Sinn machen, wieso sollte man das dann nicht erzwingen?
Von mir aus auch in der Art, wenn das möglich ist:template<typename T1, typename T2> T1::iterator copy(T2::iterator Start, T2::iterator End, T1::iterator Target);
Shade Of Mine schrieb:
Nein, ich werde jetzt keine Grundsatzdiskussion über Templates anfangen. Sorry. Dein copy macht keinen sinn, du hebelst damit das iterator konzept aus.
Mag sein, habe bisher noch nicht viel mit Iteratoren gemacht, wollte damit nur endlich (wie gefordert) auf Dein Beispiel eingehen. :p
Shade Of Mine schrieb:
Aber du lenkst die ganze Zeit vom Thema ab. Das finde ich langweilig. Ich schreibe da wirklich viel, erkläre die Sachen möglichst einfach und du ignorierst es einfach... Das ist nicht lustig
Das Gefühl hatte ich bisher eigentlich nicht.
Aber ist mir jetzt auch ehrlich gesagt ziemlich egal, ich habe das jetzt bei mir unter "Geschmacksache" abgelegt und dafür ist das Thema erstmal für mich erledigt. Falls ich Dich unwissentlich ignoriert habe, dann "Sorry". Aber wie gesagt, das Gefühl hatte ich eigentlich nicht.Wieder Frieden?
-
mantiz schrieb:
Dafür bin ja dann nicht ich zuständig, sondern der Entwickler der Funktion MoveWindow. Wobei hier im Header soweit ich weiß sogar steht: bRepaint, was die IDE ja dann auch anzeigen sollte, also ist alles klar.
Ist mir klar, aber es ist wieder so ein schöner Punkt wo man etwas mehr lesbarkeit hätte einbauen können. Du kannst daran nichts ändern, das ist klar.
wobei das hier aber eher unnötig ist ein tmp-Objekt zu erzeugen, denke ich. Zum Speichern kann man die Werte ja dann ruhig in ein struct packen.
Du hast 0 overhead, sparst dir aber arbeit wenn du die Werte auch speichern statt nur weiterreichen willst. Ist ausserdem praktischer nur ein objekt rumzureichen - denn die 4 werte gehören ja sowieso zusammen und haben getrennt keinen Sinn.
Wenn nur iteratoren Sinn machen, wieso sollte man das dann nicht erzwingen?
Von mir aus auch in der Art, wenn das möglich ist:template<typename T1, typename T2> T1::iterator copy(T2::iterator Start, T2::iterator End, T1::iterator Target);
Nein, um Stroustrup frei zu zitieren "iterator ist, was sich wie ein iterator verhält" - ein char* kann ein iterator auf einen array of char sein.
Wieder Frieden?
NEEEIIINNNN!!!!! Ihc werte dihc n00b pwnen!!!111eins
:p
-
[cpp]void moveResized(const Rectangle**&** rect)[/cpp]
die cpp tags sind kaputt
-
Shade Of Mine schrieb:
Es gibt kein aussen und innen.
Doch, es gibt den Templatecode an sich und den Clientcode. Du hast im Clientcode nirgendwo die "kryptischen" Bezeichner welche du monierst.
Und innerhalb des Templatecodes ist, allein vom Kontext her, offensichtlich was wofür steht.
In deinen folgenden Beispielen hast du Recht, da gilt es sinnvolle Bezeichner zu finden, aber das habe ich (und wohl auch sonst niemand) bestritten.
Wie PAD gesagt hat, soviel wie nötig, aber auch nicht mehr.Wie sieht's denn hiermit aus:
template <typename T> class Array { /* ... */ }; template <typename T> void swap( T& t1, T& t2 ) { /* ... */ };
Was wären denn hier z.B. sinnvolle Bezeichner? Wenn T so ungewöhnlich wäre könnte man vielleicht für Type plädieren, aber sonst?
Shade Of Mine schrieb:
Nur weil eine Methode private ist, nennen wir sie doch nicht p1 wenn ein stripInvalidSymbols() viel passender wäre, oder?
Wie nennen wir denn unsere Member Variablen?
m1, m2?
Nein, wir nennen sie value, size, speed, fuel,...Du vergleichst noch immer Äpfel mit Birnen. Siehe oben (& vorige Posts).
Sah dein erstes Beispiel wirklich so aus:template <typename T> class V { T v; }; // oder doch eher wie folgt, mit sinnvollen Bezeichnern? template <typename V> class Value { V value; };
Shade Of Mine schrieb:
Natürlich ist der Template-Type ein Platzhalter für 'etwas'. Aber dieses 'etwas' hat ja bestimmte Beschränkungen oder einen bestimmten Nutzen/Verwendungszweck.
Siehe oben. Wenn es sinnvolle Bezeichner gibt spricht alles dafür sie auch zu verwenden.
Shade Of Mine schrieb:
Das mit dem ValueType ist wie volkard schon gesagt hat, suboptimal.
Ich finde es eigentlich ganz nett ein Uppercase-T anzuhängen. Nicht optimal aber auch nicht schlimmer als ohne.
Shade Of Mine schrieb:
Nehmen wir nochmal das schöne copy Beispiel (dass ihr so gerne ignoriert):
Beim copy Beispiel macht es durchaus Sinn, ja.
Shade Of Mine schrieb:
Bei Schleifen: i, j, k, l sind (wie ich schon so oft gesagt habe) standardisierte Namen in einem engen eingeschränkten Kontext. Ein i muss immer zu einer Zählschleife gehören. Ein T muss aber nur ein Typ sein. Das ist doch etwas vage... Zumal A und C auch Typen sind, aber welche Rolle spielen sie? Keine Ahnung.
Wieso ist die i, j Konvention 'Ok'? Wäre ein aussagekräftiger Name nicht viel sinnvoller? (Ich z.B. würde bei einer Tabelle/Matrix o.ä. immer row & col den Vorzug geben, und solche Beispiele lassen sich nicht für die meisten, aber doch recht viele Schleifen finden.)
Wenn A und C Typen sind welche eine besondere Rolle spielen, siehe oben, sinnvolle Bezeichner verwenden und gut ist. Was aber wenn es wirklich mehr oder weniger irgendein Typ sein kann? Ist die Assoziation "T ^= Typ[e]" echt so dramatisch?Shade Of Mine schrieb:
Man lehrt dass sogar den Anfängern: jeder Bezeichner soll so aussagekräftig wie möglich sein. Lieber ein Wort zuviel als zu wenig. Das ist gut so, weil man den Code dadurch leichter lesen kann.
So aussagekräftig wie möglich? Ja, wenn man damit nicht mehr als nötig/sinnvoll meint.
Lieber ein Wort zuviel als zu wenig? DasWürdeIchNiemandemMitAufDenWegGeben, denn EwigLangeBezeichnerMachen DenCodeAuchNichtWirklich lesbarer.
Redundante, irrelevante oder Änderung unterworfene "Informationen" in den Bezeichner zu quetschen würde ich nicht direkt als geschickt bezeichnen.Shade Of Mine schrieb:
Nochmal meine Frage:
was kostet es, den Bezeichner einen ordentlichen Namen zu geben? Wir machen es doch überall anders auch so, oder? Warum hier nicht?Weil es zum Teil einfach unnötig/redundant ist.
Shade Of Mine schrieb:
'Weil es unnötig ist' ist eine doofe Begründung.
Mag sein dass sie doof ist, und eine 50 seitige Abhandlung wäre angemessener, aber in den Fällen wo es unnötig ist soll mir 'Weil es unnötig ist' reichen.
Shade Of Mine schrieb:
Denn es ist auch unnötig lokalen Variablen vernünftige Namen zu geben, ein char b[100] reicht doch statt einem char buffer[100] oder ein S s; statt einem string str; Wozu überhaupt lange Namen verwenden?
S ist string, also typedef std::string S; V ist vector (dass es auch Value oder Variadic oder Variant etc. heissen kann ignorieren wir natürlich)Dann sehen unsere Codes so aus:
V<C> v; v.p('a'); v.p('b'); v.p('c'); S s(v.b(), v.e()); c<<s;
geil!
Schon wieder, Äpfel und Birnen.
-
@Shade Of Mine: Dein Kung-Fu nicht gut. Keine Chance gegen meine Tiger-Affen-Drachen-Technik.
-
finix schrieb:
Shade Of Mine schrieb:
Es gibt kein aussen und innen.
Doch, es gibt den Templatecode an sich und den Clientcode. Du hast im Clientcode nirgendwo die "kryptischen" Bezeichner welche du monierst.
Wieso die Unterscheidung? Ich will überall guten Code haben.
Und innerhalb des Templatecodes ist, allein vom Kontext her, offensichtlich was wofür steht.
Bei einem Einzeiler vielleicht. Aber nicht bei einer komplexeren Funktion (was nicht bedeutet, dass sie lang ist, kann auch was komplex Mathematisches sein) oder bei einer Klasse. Da bin ich heilfroh, so viele Informationen wie möglich auf den ersten Blick zu bekommen.
In deinen folgenden Beispielen hast du Recht, da gilt es sinnvolle Bezeichner zu finden, aber das habe ich (und wohl auch sonst niemand) bestritten.
Wieso dann nicht überall? Im Clientcode machst du auch keinen Unterschied zwischen wichtigen Variablen und Hilfsvariablen. Eigentlich müssten deine Hilfsvariablen dann auch ganz kryptische Namen haben, weil ja in den fünf Zeilen, in denen sie gebraucht werden, direkt klar sein sollte, wofür sie gut sind.
Wie PAD gesagt hat, soviel wie nötig, aber auch nicht mehr.
So langsam macht es keinen Sinn mehr, in jedem zweiten Posting diesen Satz mit eigener (aber nicht schriftlich niedergelegter) Interpretation zu sehen.
Wie sieht's denn hiermit aus:
template <typename T> class Array { /* ... */ };
Data? Element?
Shade Of Mine schrieb:
Nur weil eine Methode private ist, nennen wir sie doch nicht p1 wenn ein stripInvalidSymbols() viel passender wäre, oder?
Wie nennen wir denn unsere Member Variablen?
m1, m2?
Nein, wir nennen sie value, size, speed, fuel,...Du vergleichst noch immer Äpfel mit Birnen. Siehe oben (& vorige Posts).
Sah dein erstes Beispiel wirklich so aus:template <typename T> class V { T v; }; // oder doch eher wie folgt, mit sinnvollen Bezeichnern? template <typename V> class Value { V value; };
Und wie machst dus mit lokalen Variablen? BTW: Mit Membervariablen meinte Shade wohl die privaten. Die haben einen genauso großen Gültigkeitsbereich wie ein typename T bei einer Template-Klasse. Von daher ein Vergleich von Äpfeln mit Äpfeln.
Shade Of Mine schrieb:
Natürlich ist der Template-Type ein Platzhalter für 'etwas'. Aber dieses 'etwas' hat ja bestimmte Beschränkungen oder einen bestimmten Nutzen/Verwendungszweck.
Siehe oben. Wenn es sinnvolle Bezeichner gibt spricht alles dafür sie auch zu verwenden.
Wieso widersprichst du dir selbst?
Shade Of Mine schrieb:
Bei Schleifen: i, j, k, l sind (wie ich schon so oft gesagt habe) standardisierte Namen in einem engen eingeschränkten Kontext. Ein i muss immer zu einer Zählschleife gehören. Ein T muss aber nur ein Typ sein. Das ist doch etwas vage... Zumal A und C auch Typen sind, aber welche Rolle spielen sie? Keine Ahnung.
Wieso ist die i, j Konvention 'Ok'? Wäre ein aussagekräftiger Name nicht viel sinnvoller? (Ich z.B. würde bei einer Tabelle/Matrix o.ä. immer row & col den Vorzug geben, und solche Beispiele lassen sich nicht für die meisten, aber doch recht viele Schleifen finden.)
Bei mir eigentlich so gut wie nie. Du beschäftigst dich wohl mit anderen Themen wie ich. Aber wenn ein konkreter anderer Name hilfreich ist, sollte man auch von i abweichen, klar.
Wenn A und C Typen sind welche eine besondere Rolle spielen, siehe oben, sinnvolle Bezeichner verwenden und gut ist. Was aber wenn es wirklich mehr oder weniger irgendein Typ sein kann? Ist die Assoziation "T ^= Typ[e]" echt so dramatisch?
Bei vielen Templates ist es aber nicht so, dass alle Typen eingesetzt werden können, sodass es noch Sinn macht. Ansonsten neige ich auch zum T.
Shade Of Mine schrieb:
Man lehrt dass sogar den Anfängern: jeder Bezeichner soll so aussagekräftig wie möglich sein. Lieber ein Wort zuviel als zu wenig. Das ist gut so, weil man den Code dadurch leichter lesen kann.
So aussagekräftig wie möglich? Ja, wenn man damit nicht mehr als nötig/sinnvoll meint.
Lieber ein Wort zuviel als zu wenig? DasWürdeIchNiemandemMitAufDenWegGeben, denn EwigLangeBezeichnerMachen DenCodeAuchNichtWirklich lesbarer.
Redundante, irrelevante oder Änderung unterworfene "Informationen" in den Bezeichner zu quetschen würde ich nicht direkt als geschickt bezeichnen.Schau dir mal Anfänger an. Sehr viele benutzen Abkürzungen, die keiner versteht. Von daher ist der Rat durchaus gut, weil man als Anfänger gar nicht auf die Idee kommt, ellenlange Variablennamen zu verwenden.
-
@Michael E.
i,j,k,... sind in den Naturwissenschaften ein anerkanntes Verfahren um Lauf/Schleifeindices zu bezeichnen. Warum soll man hier eine neue Konvention die vom de facto Standard abweicht definieren. Dies gilt allerdings nur für "bedeutungslose" Zählvariablen. Haben dies Zaählvariablen noch eine zusätzlichen Sinn sollte man ihnen eine sinnhaften Namen geben.n
(∑x[i])/n
i=1Gibt es hier einen Sinn dem Laufindex einen speziellen Namen zu geben ? Ich meine nein, und so sollte man es vom Prinzip her auch im Code machen
@Shade du hattest dich vorhin dafür Ausgesprochen bei der Definiton des Rechtecks, die ersten beiden Koordinaten top,left zu nennen. Ich halte es da eher mit deinem vorredner, der da sagte in einem anderen Bezugssystem könnte auch bottom left die Anfangskoordinate sein und er würde deshalb x und y bevorzugen. Aber das fällt eher unter Geschmackssache, Aber wenn du mit einer PC-graphik 0,0 links oben und mit einem Vektorterminal mit kartesischen Koordinaten 0,0 links unten arbeitest freust du dich über eine widerspruchsfrei Definition wenn du gleichlautende Routinen benutzt.
-
Michael E. schrieb:
finix schrieb:
Shade Of Mine schrieb:
Es gibt kein aussen und innen.
Doch, es gibt den Templatecode an sich und den Clientcode. Du hast im Clientcode nirgendwo die "kryptischen" Bezeichner welche du monierst.
Wieso die Unterscheidung? Ich will überall guten Code haben.
Ja, du hast natürlich völlig Recht.
Jetzt wo du es sagst.
Ich bin auch immer komplett am verzweifeln wenn ich über den Implementationsdetails von z.B. boosts shared_ptr hänge.
Naja, vielleicht auch nicht.Michael E. schrieb:
Und innerhalb des Templatecodes ist, allein vom Kontext her, offensichtlich was wofür steht.
Bei einem Einzeiler vielleicht. Aber nicht bei einer komplexeren Funktion (was nicht bedeutet, dass sie lang ist, kann auch was komplex Mathematisches sein) oder bei einer Klasse. Da bin ich heilfroh, so viele Informationen wie möglich auf den ersten Blick zu bekommen.
Ich schätze grob unten stehendes Array-Template würde, ordentlich implementiert, deutlich über einen Einzeiler hinaus gehen. Dennoch traue ich auch dir zu selbst bei der zweiten Bildschirmseite (!) noch nicht vergessen zu haben wöfür T steht.
Michael E. schrieb:
In deinen folgenden Beispielen hast du Recht, da gilt es sinnvolle Bezeichner zu finden, aber das habe ich (und wohl auch sonst niemand) bestritten.
Wieso dann nicht überall? Im Clientcode machst du auch keinen Unterschied zwischen wichtigen Variablen und Hilfsvariablen. Eigentlich müssten deine Hilfsvariablen dann auch ganz kryptische Namen haben, weil ja in den fünf Zeilen, in denen sie gebraucht werden, direkt klar sein sollte, wofür sie gut sind.
Irgendwie scheinst du immer zu versuchen alles zu verallgemeinern, Aussagen auf völlig andere Situationen zu transferieren, die so nie auch nur erwähnt wurden oder gar explizit ausgeschlossen wurden. Wie bitte schön kommst du von meiner Aussage auf eine Mutmaßung über einen ganz anderen Sachverhalt, die, wenn überhaupt, meiner Aussage komplett entgegen gesetzt ist?
Michael E. schrieb:
Wie PAD gesagt hat, soviel wie nötig, aber auch nicht mehr.
So langsam macht es keinen Sinn mehr, in jedem zweiten Posting diesen Satz mit eigener (aber nicht schriftlich niedergelegter) Interpretation zu sehen.
Häh?
Michael E. schrieb:
Wie sieht's denn hiermit aus:
template <typename T> class Array { /* ... */ };
Data? Element?
Sicherlich nette Bezeichner für die entsprechende Variable - aber für den Typ?
Davon ab, welchen Bezeichner würdest du für das zweite Beispiel vorschlagen?Michael E. schrieb:
Shade Of Mine schrieb:
Nur weil eine Methode private ist, nennen wir sie doch nicht p1 wenn ein stripInvalidSymbols() viel passender wäre, oder?
Wie nennen wir denn unsere Member Variablen?
m1, m2?
Nein, wir nennen sie value, size, speed, fuel,...Du vergleichst noch immer Äpfel mit Birnen. Siehe oben (& vorige Posts).
Sah dein erstes Beispiel wirklich so aus:template <typename T> class V { T v; }; // oder doch eher wie folgt, mit sinnvollen Bezeichnern? template <typename V> class Value { V value; };
Und wie machst dus mit lokalen Variablen? BTW: Mit Membervariablen meinte Shade wohl die privaten. Die haben einen genauso großen Gültigkeitsbereich wie ein typename T bei einer Template-Klasse. Von daher ein Vergleich von Äpfeln mit Äpfeln.
Es ging vorrangig darum noch einmal zu zeigen wie sehr der ursprüngliche Vergleich hinkt. Darüber hinaus wird sich für eine Membervariable generell ein 'bezeichnender' Name finden lassen, was bei Templateparametern nicht zwangsläufig der Fall ist.
Michael E. schrieb:
Shade Of Mine schrieb:
Natürlich ist der Template-Type ein Platzhalter für 'etwas'. Aber dieses 'etwas' hat ja bestimmte Beschränkungen oder einen bestimmten Nutzen/Verwendungszweck.
Siehe oben. Wenn es sinnvolle Bezeichner gibt spricht alles dafür sie auch zu verwenden.
Wieso widersprichst du dir selbst?
Woraus konstruierst du die Empfindung/Unterstellung ich widerspäche mir selbst?
Michael E. schrieb:
Wieso ist die i, j Konvention 'Ok'? Wäre ein aussagekräftiger Name nicht viel sinnvoller? (Ich z.B. würde bei einer Tabelle/Matrix o.ä. immer row & col den Vorzug geben, und solche Beispiele lassen sich nicht für die meisten, aber doch recht viele Schleifen finden.)
Bei mir eigentlich so gut wie nie. Du beschäftigst dich wohl mit anderen Themen wie ich. Aber wenn ein konkreter anderer Name hilfreich ist, sollte man auch von i abweichen, klar.
[/quote]
Ich bin mir nicht sicher warum du mir derart, vor allem in dieser Art und Weise, widersprichst; im weiteren Sinne ist das eine ähnliche Situation wie Bezeichner für Templateparameter zu bestimmen, lediglich mit dem Unterschied zu Euch, wie es scheint, dass ich mich auch oftmals mit einem i oder j zufrieden geben kann.Michael E. schrieb:
Wenn A und C Typen sind welche eine besondere Rolle spielen, siehe oben, sinnvolle Bezeichner verwenden und gut ist. Was aber wenn es wirklich mehr oder weniger irgendein Typ sein kann? Ist die Assoziation "T ^= Typ[e]" echt so dramatisch?
Bei vielen Templates ist es aber nicht so, dass alle Typen eingesetzt werden können, sodass es noch Sinn macht. Ansonsten neige ich auch zum T.
Wie denn, T? Nicht Type? Oder Anything? Wie wär's mit AnyType?
Michael E. schrieb:
Shade Of Mine schrieb:
Man lehrt dass sogar den Anfängern: jeder Bezeichner soll so aussagekräftig wie möglich sein. Lieber ein Wort zuviel als zu wenig. Das ist gut so, weil man den Code dadurch leichter lesen kann.
So aussagekräftig wie möglich? Ja, wenn man damit nicht mehr als nötig/sinnvoll meint.
Lieber ein Wort zuviel als zu wenig? DasWürdeIchNiemandemMitAufDenWegGeben, denn EwigLangeBezeichnerMachen DenCodeAuchNichtWirklich lesbarer.
Redundante, irrelevante oder Änderung unterworfene "Informationen" in den Bezeichner zu quetschen würde ich nicht direkt als geschickt bezeichnen.Schau dir mal Anfänger an. Sehr viele benutzen Abkürzungen, die keiner versteht. Von daher ist der Rat durchaus gut, weil man als Anfänger gar nicht auf die Idee kommt, ellenlange Variablennamen zu verwenden.
Entweder hast du meine Ausführung nicht verstanden (ein relativ kleiner Kritikpunkt, der jedoch gut in den Rahmen dieser Diskussion passt und vielleicht der von dir weiter oben erwähnten "Schriftlichen Niederlegung" nahe kommt) oder scheinst jene Überkompensation zu befürworten.
-
PAD schrieb:
@Michael E.
i,j,k,... sind in den Naturwissenschaften ein anerkanntes Verfahren um Lauf/Schleifeindices zu bezeichnen. Warum soll man hier eine neue Konvention die vom de facto Standard abweicht definieren. Dies gilt allerdings nur für "bedeutungslose" Zählvariablen. Haben dies Zaählvariablen noch eine zusätzlichen Sinn sollte man ihnen eine sinnhaften Namen geben.Mein ich ja und habs IMHO auch so ausgedrückt.
finix schrieb:
Ja, du hast natürlich völlig Recht.
Jetzt wo du es sagst.
Ich bin auch immer komplett am verzweifeln wenn ich über den Implementationsdetails von z.B. boosts shared_ptr hänge.
Naja, vielleicht auch nicht.Wenn du ihn selbst verändern willst, dann ja (BTW: keine Ahnung, wie schlimm der Code von shared_ptr ist). Du brauchst nicht so zu tun, als würdest du grad nur noch ne Hauptfunktion schreiben und den Rest von Libraries inkludieren, du hast nämlich auch Implementierungen, die du mit "innen" umschreibst. Von daher ist dein Beispiel daneben.
Ich schätze grob unten stehendes Array-Template würde, ordentlich implementiert, deutlich über einen Einzeiler hinaus gehen. Dennoch traue ich auch dir zu selbst bei der zweiten Bildschirmseite (!) noch nicht vergessen zu haben wöfür T steht.
Danke. Ich traue auch dir zu, dass du das mit Typnamen T bis Z hinkriegst. Die Frage ist nur, ob es anders nicht effizienter und einfacher wäre.
Irgendwie scheinst du immer zu versuchen alles zu verallgemeinern, Aussagen auf völlig andere Situationen zu transferieren, die so nie auch nur erwähnt wurden
Ich mache das, um dir deine Inkonstistenz an analogen Beispielen zu zeigen.
oder gar explizit ausgeschlossen wurden.
Wo?
Wie bitte schön kommst du von meiner Aussage auf eine Mutmaßung über einen ganz anderen Sachverhalt, die, wenn überhaupt, meiner Aussage komplett entgegen gesetzt ist?
Ich erkenne eindeutig eine Analogie. Wo siehst du den Gegensatz?
Michael E. schrieb:
So langsam macht es keinen Sinn mehr, in jedem zweiten Posting diesen Satz mit eigener (aber nicht schriftlich niedergelegter) Interpretation zu sehen.
Häh?
Ich meine damit, dass der Satz schon von beiden Seiten gebracht wurde, bloß unterschiedlich ausgelegt wird. Leider macht es dann ohne explizite Auslegung keinen Sinn mehr, diesen Satz noch öfter zu zitieren.
Michael E. schrieb:
Wie sieht's denn hiermit aus:
C/C++ Code:
template <typename T>
class Array
{ /* ... */ };
C/C++ Code:
template <typename T>
class Array
{ /* ... */ };
C/C++ Code:
template <typename T>
class Array
{ /* ... */ };Data? Element?
Sicherlich nette Bezeichner für die entsprechende Variable - aber für den Typ?
Man hat ja schon vorher gesehen, dass du ein Postfix-T oder -Type magst. Also meinetwegen ElementType.
Davon ab, welchen Bezeichner würdest du für das zweite Beispiel vorschlagen?
T.
Darüber hinaus wird sich für eine Membervariable generell ein 'bezeichnender' Name finden lassen, was bei Templateparametern nicht zwangsläufig der Fall ist.
Deshalb hab ich ja auch geschrieben, dass man einen guten Namen suchen soll und wenn man keinen findet, kommt meinetwegen T.
Michael E. schrieb:
Siehe oben. Wenn es sinnvolle Bezeichner gibt spricht alles dafür sie auch zu verwenden.
Wieso widersprichst du dir selbst?
Woraus konstruierst du die Empfindung/Unterstellung ich widerspäche mir selbst?
Daraus, dass du ein T/U/V sinnvolleren Namen vorziehst.
Michael E. schrieb:
Wieso ist die i, j Konvention 'Ok'? Wäre ein aussagekräftiger Name nicht viel sinnvoller? (Ich z.B. würde bei einer Tabelle/Matrix o.ä. immer row & col den Vorzug geben, und solche Beispiele lassen sich nicht für die meisten, aber doch recht viele Schleifen finden.)
Bei mir eigentlich so gut wie nie. Du beschäftigst dich wohl mit anderen Themen wie ich. Aber wenn ein konkreter anderer Name hilfreich ist, sollte man auch von i abweichen, klar.
Ich bin mir nicht sicher warum du mir derart, vor allem in dieser Art und Weise, widersprichst; im weiteren Sinne ist das eine ähnliche Situation wie Bezeichner für Templateparameter zu bestimmen, lediglich mit dem Unterschied zu Euch, wie es scheint, dass ich mich auch oftmals mit einem i oder j zufrieden geben kann.
Ich arbeite auch mit i/j/k. Guck mal, was PAD geschrieben hat:
PAD schrieb:
i,j,k,... sind in den Naturwissenschaften ein anerkanntes Verfahren um Lauf/Schleifeindices zu bezeichnen. Warum soll man hier eine neue Konvention die vom de facto Standard abweicht definieren.
Mit i/j/k weiß jeder sofort, was damit gemeint ist, und, was noch viel wichtiger ist, wie es sich verhält. Bei Typnamen ist das Verhalten nicht klar, deshalb versucht man es durch passende Namen näher zu erläutern.
Wie denn, T? Nicht Type? Oder Anything? Wie wär's mit AnyType?
Weil Type/Anything/AnyType weder genauer spezifizieren, was ich gerne als Übergabe hätte, noch der Leserlichkeit dienen.
Entweder hast du meine Ausführung nicht verstanden (ein relativ kleiner Kritikpunkt, der jedoch gut in den Rahmen dieser Diskussion passt und vielleicht der von dir weiter oben erwähnten "Schriftlichen Niederlegung" nahe kommt) oder scheinst jene Überkompensation zu befürworten.
OK, nochmal: Anfänger neigen dazu, kurze und unverständliche Variablennamen zu benutzen. Durch dieses "Lieber ein Wort zuviel als zu wenig" bringt man sie überhaupt erst mal auf verständliche Namen. Die Variablennamen werden also sozusagen auf Fortgeschrittenen-Niveau angepasst. Dass Variablennamen durch diesen Lehrsatz zu lang werden, sieht man eher selten.
-
ihr seid komplett durchgeknallt
-
net schrieb:
ihr seid komplett durchgeknallt
Nein, wir sind Gurus.