Sinn und Unsinn der ungarischen Notation



  • groovemaster schrieb:

    CStoll schrieb:

    Wie sehen denn dann solche Präfixe/Suffixe der UN aus, die die Aufgabe der Variable beschreiben?

    z.B. i für Index (das kann int, long oder size_t sein)

    Mal abgesehen davon, dass ich mich hier fragen würde, ob das i nun für Index, int, Iterator oder was auch immer steht, welchen konkreten Nutzen hast du davon?

    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).
    (btw, 'int' hat bei der Namenswahl nichts zu suchen (wäre bestenfalls n (numerisch), Iteratoren würde ich mit p kennzeichnen.

    CStoll schrieb:

    oder a für Array (aus logischer Sicht - muß also nicht unbedingt ein C-Array sein).

    Es gibt unzählige Container, Arrays, Sequenzen, Listen, Maps, Queues, Stacks, etc.pp. Wer soll denn da bitteschön durchblicken? Mich interessiert hier doch lediglich eines, welche Member stehen mir zur Verfügung. Bzw. was kann ich mit diesem Container anfangen. Und dazu reicht maximal ein Blick auf die Deklaration, um den Typ zu erfahren. Über die genaue Funktionsweise des Containers sagt so ein Präfix auch nichts aus. Dann heisst es, sich die entsprechende Doku durchzulesen.

    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).

    @byto: Hinter "Weights" kann wahlweise ein struct (mit Leergewicht, Maximalgewicht etc eines Objekts) oder ein Array (mit Gewichten verschiedener Gegenstände) stehen.



  • foo = bar[baz];
    

    Verdammt was könnte dieser Coede blos bedeuten? Keine Ahnung, da könnte echt mal jemand sowas, wie i und a dran schreiben

    foo = aBar[iBaz];
    

    Ah, jetzt verstehe ich den Code endlich.



  • 👍 😃



  • Hallo

    Helium schrieb:

    foo = bar[baz];
    

    Verdammt was könnte dieser Coede blos bedeuten? Keine Ahnung, da könnte echt mal jemand sowas, wie i und a dran schreiben

    foo = aBar[iBaz];
    

    Ah, jetzt verstehe ich den Code endlich.

    Sehr schön. Das fasst die Diskussion gut zusammen.

    chrische



  • chrische5 schrieb:

    Hallo

    Helium schrieb:

    foo = bar[baz];
    

    Verdammt was könnte dieser Coede blos bedeuten? Keine Ahnung, da könnte echt mal jemand sowas, wie i und a dran schreiben

    foo = aBar[iBaz];
    

    Ah, jetzt verstehe ich den Code endlich.

    Sehr schön. Das fasst die Diskussion gut zusammen.

    chrische

    Es fasst vor allem das Niveau der Diskussion gut zusammen.



  • Tim schrieb:

    Es fasst vor allem das Niveau der Diskussion gut zusammen.

    diese 'diskussion' erinnert verdächtig an das, was man in NADRW immer so vorgesetzt bekommt.
    🙂



  • Helium schrieb:

    foo = bar[baz];
    

    Verdammt was könnte dieser Coede blos bedeuten? Keine Ahnung, da könnte echt mal jemand sowas, wie i und a dran schreiben

    foo = aBar[iBaz];
    

    Ah, jetzt verstehe ich den Code endlich.

    😃 👍

    Noch nie wurden die Geister so gespalten wie bei den U-Notation. Ob der Ungar sich das so vorgestellt hatte? Er wollte die Welt nur bereichern, wollte die Welt zu einem besserem Ort machen, nach seinen Vorstellungen. Wer konnte ahnen das im Jahre 2008 der Disput so einen tragischen Ausgang nehmen wuerde: Der Erste Ungarische-Notation-Weltkrieg.

    Ausgeloest von einem Chat im #cpp Channel konnte ein Anhaenger dieser grandiosen Ungarischen Notationen nicht mehr die Schmaelungen seitens der Ahnunglosen hinnehmen. Niemand in diesem Channel konnte ja auch Ahnen das der groesste Fan der U-Notation in einem Stuetztpunkt der USA arbeitet, bei dem er die Aufsicht ueber die Kernwaffen haellt.

    Wird dies das Ende der Menschheit sein? Werden unsere Kindeskinder einmal Geschichten hoeren ueber den groessten Disput der 1972-1981 seinen Ursprung nahm? Werden sie es als den groessten Fehler in der Weltgeschichte wahrnehmen?

    Und vor allem: Werden diese sinnlosen Threads ueber die noch sinnloserenen U-Notationen endling der Geschichte angehoeren???



  • http://msdn2.microsoft.com/en-us/library/aa260976(VS.60).aspx

    if (cch>=2)
             cwSz=(cch-2/sizeof(int)+1;
          *pbsy=(int *)(psy=PsyCreate(cwSY+cwSz))-rgwDic;
          Zero((int *)psy,cwSY);
          bltbyte(sz, psy->sz, cch+1);
          return(psy);
    

    Jepp, UN machen alles so viel lesbarer.



  • ich finde code mit ungarischer notation grundsätzlich grauslig und unübersichtlich.

    grauslig, weil sich in jeden code früher oder später an einer oder mehreren stellen ein bruch findet. da ändert irgendjemand mal kurz eine signatur oder einen typ, vergisst dabei, die prefixe der variablen anzupassen und schon kann man sich im gesamten code nicht mehr darauf verlassen, dass eine variable namens iUpdCmp tatsächlich einen integer beinhaltet.

    unübersichtlich, weil dieses prefixgedöns den lesefluss extrem beeinflusst. und klassische c-programmierer neigen dazu, variablen abkürzende namen zu geben (iUpdCmp), die wenig aussagekraft haben, wenn man nicht den gesamten kontext kennt. anstatt sich mit ungarischer notation rumzukloppen, sollte man seinen variablen und methoden einfach anständige und verständliche namen geben. eine methode namens i2c ist vielleicht kurz und spart tipparbeit, aber dieselbe methode in integerToCharacter umbenannt zeigt sofort eindeutig, was sie tun soll. wenn man sich an ungarische notation hält, kann man sie meinetwegen auch characterFromInteger nennen.

    musste die letzten wochen sehr viel alten c-code nach java portieren und der grossteil dieses codes war von ungarischer notation verseucht. der code, der einfach anständige bezeichner verwendet hat, war wesentlich schneller zu verstehen und auch zu portieren.



  • dann sollte man statt "iUpdCmp" (int) ein "nUpdCmp" (mueric) verwenden
    richtig angewended ist die UN richtig gut - sofern der name nicht auch zerstueckelt wird

    man kann zwar "i2c (integer to char)" zu "IntegerToChar" aendern, aber was aendert das ?
    wenn man die variablen erst untersuchen muss was sie representieren, kann man genauso nachschaun was i2c macht, kommt aufs selbe
    angenommen die funktion wird mehrmals ueberladen
    "x2c (something to char)", da schreib ich ja auch nicht "SomethingToChar" oder dergleichen.

    wie gesagt, die UN ist sehr gut, wenn sie richtig angewendet wird
    man kombiniert das, aussagekraeftige namen + UN zuvor

    was des beispiel von der MSDN angeht, ich verstehs nicht da ist ein int als cch deklariert, macht irgendwie kein sinn, dementsprechend ignorier ich das schlichtweg.
    alles extrem abgekuerzt ist grausig.



  • 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.



  • Es gibt doch diesen Artikel über die "hungarian warthogs" hat von euch noch jemand die URL von dem?



  • Mr Evil schrieb:

    wie gesagt, die UN ist sehr gut, wenn sie richtig angewendet wird
    man kombiniert das, aussagekraeftige namen + UN zuvor

    naja, ich bleib dabei, dass ich die prefix notation für überflüssig halte. die "original" UN konventionen, die schlicht für konsistenz im code sorgen wollen (z.B. worldFromScreen(int, int) statt screenToWorld(int, int)) sind hingegen nicht verkehrt.

    um code zu verstehen ist es eh meist nicht wichtig zu wissen, welcher typ tatsächlich verwendet wird, sondern wofür eine variable verwendet wird.

    um das screenToWorld thema nochmal aufzugreifen:

    pPnt = screenToWorld(nX, nY);
    // vs.
    worldPnt = worldFromScreen(screenX, screenY);
    

    das ist, was UN mal erreichen wollte. nicht typen, sondern verwendung und herkunft.



  • Was ist denn der Unterschied zwischen (achtung erste Zeile von mir geändert!)

    worldPnt = screenToWorld(screenX, screenY);
    // vs.
    worldPnt = worldFromScreen(screenX, screenY);
    


  • der unterschied ist adjazenz von semantischen inhalten.

    worldPnt = screenToWorld(screenX, screenY);
    screenPnt = screenToWorld(worldX, worldY); // fehler!
    
    // vs.
    
    worldPnt = worldFromScreen(screenX, screenY);
    screenPnt = worldFromScreen(worldX, worldY); // fehler!
    

    wenn man sich an letztere konvention hält, dann kann man sich einfach merken, immer dann mistrauisch zu werden, wenn zwei unterschiedliche prefixes links und rechts einer zuweisung stehen. das sticht mehr ins auge.



  • thordk schrieb:

    die "original" UN konventionen, [...] sind hingegen nicht verkehrt.

    Ja, die Genfer Konventionen sind toll 😃 *scnr*

    Felix



  • Mal eine Frage an die pro-UN: Wieso es wichtig ob eine Variable ein Pointer ist oder nicht? Normalerweise prueft es doch der Compiler nach:

    int *irgendwas;
    // ...
    irgendwas = 50; // kommt hier denn keine Warnung? 
    // bzw. kommt hier kein Fehler des Compilers?
    // in einem C++ Compiler sollte da ein Fehler kommen,
    // denn in 99,99999999999999% ist es Fehler.
    
    EineKlasse *irgendwas;
    irgendwas.methode(); // hier kommt ein Compiler-Fehler
    

    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.



  • 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.


Anmelden zum Antworten