Sinn und Unsinn der ungarischen Notation
-
CStoll schrieb:
Ich sehe auf einen Blick, was die Aufgabe der Variablen ist (besonders wenn der Name zu dem Datenfeld passt, in das ich indizieren will - iNamesXyz ist ein Index, der sich auf das Array aNames bezieht).
Diese Art der Verwendung erkenne ich anhand der Semantik. Dazu muss ich keine weitere Konvention benutzen.
CStoll schrieb:
Und wo ist das Problem? Ich betrachte "Array" nicht im Sinne eines C-Arrays, sondern abstakter als einen Container, auf den ich über Index zugreifen kann (std::vector, std::deque, CObArray etc), Container mit eingeschränkten Zugriffsmöglichkeiten bekommen ihre eigenen Kürzel (z.B. ls für list<>artige oder mp für Maps).
Und was soll das? Ein Container ist für mich eine Black Box, der braucht keine Klassifizierung. Der ist absolut selbstredend. Und Map ist nicht gleich Map, genauso wenig wie Liste nicht gleich Liste ist. Weder die Implementierung noch die Funktionsweise. Solche Zusätze bringen mir exakt _nichts_.
Mr Evil schrieb:
dann sollte man statt "iUpdCmp" (int) ein "nUpdCmp" (mueric) verwenden
Das macht es auch nicht besser. Was ist denn nUpdCmp? Ein Zähler? Ein Index? Eine Länge? Was nun? Schreib es aus und fertig. Upd..C..mp..Count oder ähnliches beseitigt solche Unklarheiten.
Mr Evil schrieb:
"x2c (something to char)", da schreib ich ja auch nicht "SomethingToChar" oder dergleichen.
Nein, du schreibst einfach ToChar.
-/- schrieb:
Mr Evil schrieb:
richtig angewended ist die UN richtig gut -
Mr Evil schrieb:
wie gesagt, die UN ist sehr gut, wenn sie richtig angewendet wird
Nein, es wird einfach nicht wahrer. Auch nicht, wenn man es ständig wiederholt.
So konkret wollte ich es eigentlich nicht sagen, trifft es aber ziemlich gut.
-
groovemaster schrieb:
CStoll schrieb:
Und wo ist das Problem? Ich betrachte "Array" nicht im Sinne eines C-Arrays, sondern abstakter als einen Container, auf den ich über Index zugreifen kann (std::vector, std::deque, CObArray etc), Container mit eingeschränkten Zugriffsmöglichkeiten bekommen ihre eigenen Kürzel (z.B. ls für list<>artige oder mp für Maps).
Und was soll das? Ein Container ist für mich eine Black Box, der braucht keine Klassifizierung. Der ist absolut selbstredend. Und Map ist nicht gleich Map, genauso wenig wie Liste nicht gleich Liste ist. Weder die Implementierung noch die Funktionsweise. Solche Zusätze bringen mir exakt _nichts_.
Also ich mach das so:
Map<Key, Value> personenNamen; // man merkt das es ein Container ist, weil es Namen sind (mehrzahl) personenNamen.put(:ehefrau, "Julia"); // personenNamen hat das Interface "put(key, value)", daran weis ich das es eine Map ist. name = personenNamen.get(:ehefrau); name = personenNamen.get(0); // funktioniert nicht, weil es kein get(index) gibt List<Values> personenNamen; // wieder irgendein Container, weil mehrzahl personenNamen.push("Julia"); // personenNamen hat das Interface "puash(value)", daran merk ich das es eine Liste ist personenNamen.put(...) // funktioniert nicht, weil es put nicht gibt name = personenNamen.get(:ehefrau); // funktioniert nicht, weil es get(key) nicht gibt name = personenNamen.get(0); // funktioniert, weil es get(index) gibt
Also wozu muss ich wissen ob personenNamen nun eine Liste oder eine Map ist? Ich muss nur wissen welches Interface mir personenNamen zu verfuegung stellt.
Ein Typ definiert sich nunmal nur dadurch was ich mit ihm machen kann (sein Interface). Wie er es macht, oder wie er was speichert, interessiert mich nicht. Das gilt auch fuer Built-In-Typen wie int oder float.
Persoehnlich favorisiere ich den Java-Style.
- Typen sind Namen, Grossgeschrieben
- Interface ist meinst Name + -able: Iterable, Comparable, Loadable
- Variablen werden klein geschrieben und sind nach dem benannt was sie speichern
- fuer Laufvariablen: i,j,k,l,...
- fuer temporaere Variablen: tmpstr, tmp, tmpirgendwas
- Member-Variablen Kleingeschrieben: personenNamen, vorname, alter
- Container-Variablen sind immer in der Mehrzahl-Form: namen, daten, locations
- Methoden sind Verben, kleingeschrieben: toString(), oeffneDatei(), getAlter()
-
DEvent schrieb:
groovemaster schrieb:
CStoll schrieb:
Und wo ist das Problem? Ich betrachte "Array" nicht im Sinne eines C-Arrays, sondern abstakter als einen Container, auf den ich über Index zugreifen kann (std::vector, std::deque, CObArray etc), Container mit eingeschränkten Zugriffsmöglichkeiten bekommen ihre eigenen Kürzel (z.B. ls für list<>artige oder mp für Maps).
Und was soll das? Ein Container ist für mich eine Black Box, der braucht keine Klassifizierung. Der ist absolut selbstredend. Und Map ist nicht gleich Map, genauso wenig wie Liste nicht gleich Liste ist. Weder die Implementierung noch die Funktionsweise. Solche Zusätze bringen mir exakt _nichts_.
Also ich mach das so:
Map<Key, Value> personenNamen; // man merkt das es ein Container ist, weil es Namen sind (mehrzahl) personenNamen.put(:ehefrau, "Julia"); // personenNamen hat das Interface "put(key, value)", daran weis ich das es eine Map ist. name = personenNamen.get(:ehefrau); name = personenNamen.get(0); // funktioniert nicht, weil es kein get(index) gibt List<Values> personenNamen; // wieder irgendein Container, weil mehrzahl personenNamen.push("Julia"); // personenNamen hat das Interface "puash(value)", daran merk ich das es eine Liste ist personenNamen.put(...) // funktioniert nicht, weil es put nicht gibt name = personenNamen.get(:ehefrau); // funktioniert nicht, weil es get(key) nicht gibt name = personenNamen.get(0); // funktioniert, weil es get(index) gibt
Also wozu muss ich wissen ob personenNamen nun eine Liste oder eine Map ist? Ich muss nur wissen welches Interface mir personenNamen zu verfuegung stellt.
Ein Typ definiert sich nunmal nur dadurch was ich mit ihm machen kann (sein Interface). Wie er es macht, oder wie er was speichert, interessiert mich nicht. Das gilt auch fuer Built-In-Typen wie int oder float.
Siehst du - da brauchst du schon eine Unterscheidung. Selbst wenn du vielleicht einen bestimmten Datentyp mit "Map" verbindest, ging es mir mehr um das allgemeine Konzept (Array - sequentielle Speicherung (C-Array, std::vector, CArray o.ä.), Liste - verkettete Liste von Elementen (std::list, CList o.ä.), Map - assoziativer Container (std::map, CMap)), was man da auswählt, wird durch den Verwendungszweck bestimmt. Die Unterscheidung, welchen konkreten Typ ich nun verwenden will, kommt später (und hat auf die UN keinen Einfluß).
Und wenn dein Projekt etwas größer wird, hast du zumindest einen Orientierungspunkt, um das verfügbare Interface herauszufinden.
PS: Die erwähnte Unterscheidung Screen-Koordinaten vs. Welt-Koordinaten ist ein gutes Beispiel, wo man am Typ nicht erkennen kann, wozu die Variable dient - da muß man die Verwendung im Namen kennzeichnen.
-
man muss auch die fehler mit bedenken die der compiler zwar zeigt, aber man kann nicht immer gleich test compilieren,
ich baue hier an sachen mit die compilieren gleich ma ne halbe stunde, und zudem koennte ich auf mein system das ding gar nicht bauen
da schreib ich code so hin, und kann nicht den compiler fragen ob alles in ordnung ist
wenn da eine funktion ein zeiger haben will {die funktion ist nicht von mir}
und ich hab eine variable "bla" {diese auch auch nicht von mir}
muss ich halt wissen - muss ich "bla" oder "&bla" machen, das muss ich wissen ohne den compiler fragen zu koennenzu dem beispiel mit der map und der liste
wenn ich mir eine strategie ausdenke, will benutzen und dann
bla.push - "was, push gibts nicht, misst, muss ich meine strategie umstellen"
das problem ist, die bla liste oder map kahm auch nicht von mir, ich muss viel benutzen was ich bekomm, und wenn ich mir eine strategie ausdenke, muss ich wissen womit ich arbeite, da kann ich nicht einfach schauen ob ich put oder push verwende da sich die container anders verhaltendaher find ich es sehr gut das es hier alle so machen ein p fuer ein zeiger anzuhaengen, oder m fuer map, v fuer vector usw {ist zwar spezifischer auf den container typ, aber der wird eh nicht geaendert, waere viel zu komplex}
//dazu edit
Was ich noch voellig vergas, sehr oft hab ich auch den fall das ich quelltext im editor durchsuche, nicht in einer IDE - zb wenn ich ein fehler suche {aber nach dem finde nur weiterreiche} such ich oft den quelltext so durch, da bin ich auch nicht der einzigste
oder "mal schnell was nachschauen" ohne gleich die IDE anzuwerfen, sondern einfach auswaehlen und F3 {total commander}, gleich IDE anschmeissen nur weil jemand keine UN benutzt hat ist grausig, besonders wenn ich direkt die datei aus CVS oder Perforce anschau ohne das ganze projekt auszuchecken - ohne UN ist man da ziemlich aufgeschmissen
-
klar, oder wenn man sich mit dem schwarz-grün monitor über die serielle schnittstelle an den mainframe hängt...
aber mal im ernst. das was du da beschreibst klingt einfach nach ner schlechten arbeitsumgebung. vielleicht kannst du mit ungarischer notation da ja ein paar symptome bekämpfen, aber das dürfte es dann wohl auch schon gewesen sein.
-
Jester schrieb:
klar, oder wenn man sich mit dem schwarz-grün monitor über die serielle schnittstelle an den mainframe hängt...
...oder man in einem Stapel Hollerith-Lochkarten nach einem Programmfehler sucht
-
DEvent schrieb:
personenNamen.put(:ehefrau, "Julia"); // personenNamen hat das Interface "put(key, value)", daran weis ich das es eine Map ist.
...
personenNamen.push("Julia"); // personenNamen hat das Interface "push(value)", daran merk ich das es eine Liste istalso probierst du erst alles durch oder wie?
-
DEvent meint wohl eher den Worst-Case: keine Doku, Codecompletion u.ä. vorhanden.
Aber ich will ja nichts sagen: in C++ hab ich immer eine Doku: die header-Datei! Da kann ich im schlechtesten Fall reinschauen und muß nichts raten. Noch ein Grund weniger für die UN.Im Regelfall (sorry für die Notepad-Fanatiker) habe ich eine Codecompletion, die mir alle Methoden auflistet, wenn ich . oder -> eintippe. In der MSDN kann ich sogar on-the-fly-Doku einblenden lassen. Oder ich schaue (wenn das die IDE nicht kann) in die richtige Doku rein, die z.B. im Doxygen-Format vorliegt. Ist keine Docu vorhanden, benutze ich die Library auch nicht wirklich
ist für mich gestorben! Oder ich jage halt Doxygen selber drüber und schau mir das im Browser an.
Ich bezweifel mal, das man in einer normalen Umgebung raten muß, wie ein Interface aussieht.
-
Ich wollte Euch diese Schönheit nicht vorenthalten, leider ist sie nicht mehr ganz authentisch, man darf sich Kommentare wie
// aber Hallo! // ++ ist Hochzählen // bist Du der Zeiger? // Du bists!
an beliebigen, möglichst unpassenden Stellen einstreuen, nicht vergessen, die Einrückungen wieder vogelwild zu stellen und man kommt dem vollen Erlebnis nahe. Das Projekt habe ich von einem Ex- Telekomiker geerbt, der in einem anderen Laden "so" zu programmieren begonnen hat. Ich habe jetzt nur ein Highlight herausgenommen, aber als der Typ gegangen ist, hat er etliche zehntausend Zeilen so hinterlassen. Es hat lange gedauert, anstelle dessen les- und wartbaren Code zu erhalten. Es macht also Sinn, Konventionen aufzustellen und einzuhalten. Ob in diesem Fall UN etwas gerettet hätte, wer weiß?
OK, hier das Prachtstück:
struct ruck_zuck { void (*ruck_zuck_zeig) (void); unsigned int idee; struct ruck_zuck *vor_zuck; // ?? }; static struct ruck_zuck *ruck_zuck_start = NULL; // ?? static struct ruck_zuck *ruck_zuck_raus = NULL; // ?? static char ruck_zucks = 0; static unsigned int ruck_zuck_idee = 0; char TicktackNeuZuck( void (*zeig) (void) ) { struct ruck_zuck *ruck_zuck_zuck = malloc(sizeof(struct ruck_zuck)); // ?? if (ruck_zuck_zuck) { ruck_zuck_zuck->ruck_zuck_zeig = zeig; ruck_zuck_zuck->idee = ++ruck_zuck_idee; ruck_zuck_zuck->vor_zuck = NULL; TICKTACKAUS if (ruck_zucks) ruck_zuck_raus->vor_zuck = ruck_zuck_zuck; else ruck_zuck_start = ruck_zuck_zuck; ruck_zuck_raus = ruck_zuck_zuck; ruck_zucks++; TICKTACKEIN return ruck_zucks; } else return 0; } #pragma INTERRUPT Ticktack void Ticktack(void) { struct ruck_zuck *ruck_zuck_zahl; if (ruck_zucks) { ruck_zuck_zahl = ruck_zuck_start; while (ruck_zuck_zahl) { (*ruck_zuck_zahl->ruck_zuck_zeig)(); ruck_zuck_zahl = ruck_zuck_zahl->vor_zuck; } } } void zack(void) { // ... sth } void main(void) { // ... TicktackNeuZuck(zack); // ... }
-
@pointercrash() geil
Ich bin Java und Eclipse verwoehnt. Kompelieren On the Fly und Codeverfollstaendigung 4tw.
-
DEvent schrieb:
Mal eine Frage an die pro-UN: Wieso es wichtig ob eine Variable ein Pointer ist oder nicht?
bin nicht pro UN. aber ich kenne den grund.
siehe
int* derKleinere(int* a,int* b){ if(a<b) return a; else return b; }
und
int* derKleinere(int* pa,int* pb){ if(pa<pb)//ah, hier ist *pa,*pb gefragt return pa; else return pb; }
also der anfänger vermeidet dabei diesen fehler. und der kommt schon recht häufig vor bei den ersten zeiger-experimenten.
Ausserdem wieso in C++ nakte Zeiger anfassen? Das ist doch fast nie noetig, ein Interface sollte sowieso nie, nie, nie mit nakten Zeigern hantieren. In boost gibts es fuer jede denkbare Situation ein Zeiger-Wrapper und es gibt bei sowas 0 perfomance-Verlust.
natürlich benutzte ich zeiger. aber das ist eine andere geschichte.
-
int* derKleinere(int* pa,int* pb){ if(pa<pb)//ah, hier ist *pa,*pb gefragt return pa; else return pb; }
Kommt da keine Warnung?
-
volkard schrieb:
DEvent schrieb:
Mal eine Frage an die pro-UN: Wieso es wichtig ob eine Variable ein Pointer ist oder nicht?
bin nicht pro UN. aber ich kenne den grund.
siehe...
Wobei man hier nicht argumentieren kann das die UN an dieser Stelle unbedingt Sinn macht, da der Variablenname an sich schon nichts Aussagend gewählt wurde.
cu André
-
asc schrieb:
Wobei man hier nicht argumentieren kann das die UN an dieser Stelle unbedingt Sinn macht, da der Variablenname an sich schon nichts Aussagend gewählt wurde.
ändere es und nimm bessere namen. vielleicht so?
int* derKleinere(int* pDerEineWert,int* pDerAndereWert){ if(pDerEineWert<pb)//ah, hier ist *pDerEineWert,*pDerAndereWert gefragt return pDerEineWert; else return pDerAndereWert; }
wie aussagekräftig können variablennamen sein an kleinen funktionen wie swap?
ich erwarte von dir jetzt so gute namen, dass man die UN nicht braucht. wird es nur daraufhinauslaufen, daß du zeigerAufA statt pa nimmst?
-
volkard schrieb:
...
wie aussagekräftig können variablennamen sein an kleinen funktionen wie swap?ich erwarte von dir jetzt so gute namen, dass man die UN nicht braucht. wird es nur daraufhinauslaufen, daß du zeigerAufA statt pa nimmst?
Im Zweifel das, wobei man natürlich auch argumentieren kann das eine so kurze Funktionen auch garkeine Kennzeichnung für Zeiger brauchen. Wenn es wichtig ist das es sich um einen Zeiger handelt, dann schreibe ich dies auch im Namen rein.
Wobei ich gestehe das obwohl ich die UN ablehne 2 Dinge doch noch nach UN mache (I für Interface/Schnittstelle und bei so kleinen Funktionen tatsächlich noch manchmal p, aber klare Bezeichner ziehe ich dennoch vor - auch wenn es mehr Tiparbeit bedeuten kann).
Spätestens wenn es um Templates geht hat man aber hier sowohl mit einer sprechenden Benennung als auch mit der UN keine Chance mehr.
cu André
-
asc schrieb:
Spätestens wenn es um Templates geht hat man aber hier sowohl mit einer sprechenden Benennung als auch mit der UN keine Chance mehr.
Jein, eigentlich schon vorher, dazu hatte ich ja das Beispiel aus der Praxis angeführt - der Code hat übrigens wirklich funktioniert. Den absoluten Urzustand habe ich nicht mehr gefunden, da hatte ich schon eingerückt, Makros auf Großbuchstaben umgestellt usw. und mich dann hingesetzt, um mit Unterstützung des Debuggers herauszufinden, was die Codeteile überhaupt tun, um dann nach den Konventionsblättchen aussagekräftige Namen zu vergeben.
Will sagen, hätte der Typ sein Zeug der UN folgend aufgezogen, wäre mir "pRuckzuckzuck" genauso kryptisch wie "ruck_zuck_zuck" geblieben. Gegen gewaltsam verunstalteten Code hilft UN also gar nix :p
Nehmen wir den Fall an, daß wir einen Coder haben, der alles richtig machen will, der wird aber häufiger Gewissensentscheidungen treffen müssen, welches Präfix jeweils das aussagekräftigere ist, das liegt im Tendenzbereich. Sicher wird der das Projekt Übernehmende tendenziell auf andere Dinge Wert legen als sein Vorgänger
. Ob er die Präfixe des Vorgängers als Hilfe betrachten wird?
Was mich ad hoc gestört hat, daß man einerseits bei der UN auf Wertebereiche abzielt und dann aber andererseits Maschinenwortbreite festlegt. Schonmal eine zweite Inkonsistenzschwäche - es sind mehr zu finden. Kommt davon, wenn man für C, C++, Pascal usw. gemeinsam eine Konvention festlegen will.
Das größte Problem ist jedoch, schon von anderen erwähnt, daß bei kleinen Änderungen auch die Präfixe nachgepflegt werden wüssen und wer ist noch nie über eigene kleine Schlampereien dieser Art gestolpert?
Damit kann die "Hilfe" sogar zusätzlich die Lesbarkeit verschlechtern.
UN soll eine Lesehilfe sein, mag sein, wenn jemand mit einem Editor und dem nackten Compiler bewaffnet unter DOS loszieht, aber wenn sogar IDEs für embedded- Prozessoren einem den ganzen Kontext als Tooltip beim Mouse- Flyover reindrücken, wird die UN nur Fleißarbeit für Tippselige.
Prädikat UNsinn