Ungarische Notation - Ein großes Missverständniss



  • Meiner Meinung nach ist die Ungarische Notation -im ursprünglichen Sinne von Charles Simonyi, nämlich "Apps Hungarian"- an Übersichtlichkeit und lesbarem Code unübertroffen. Leider wurde Sie von Microsoft und Generationen von Programmierern missverstanden.

    Schade.

    Eure Meinung?



  • Hast du zufällig gute Links, die sich mit dieser (originalen) Notation beschäftigen?



  • Jep, hab' ich.

    http://www.joelonsoftware.com/printerFriendly/articles/Wrong.html

    Imho eine der besten Erklärungen die im Web zu finden sind.



  • ist ha großartig, daß man damit diese ganzen signed/unsigned-Fehler auf einen Blick sieht. Aber da ich auf Compiler-Warnungen großen Wert lege und mich mein Compiler bei sowas warnt sehe ich den Vorteil nicht.



  • s = Request("name")
    
        ...pages later...
        name = s
    
        ...pages later...
        recordset("name") = name // store name in db in a column "name"
    
        ...days later...
        theName = recordset("name")
    
        ...pages or even months later...
        Write theName
    

    Did we remember to encode the string? There’s no single place where you can look to see the bug.

    Der Mensch scheint ja echt was verstanden zu haben 🙄 .

    Weiter unten:

    In general, I have to admit that I’m a little bit scared of language features that hide things.

    Ja, das erklärt einiges.



  • Zumindest für die in dem Artikel angegebenen Beispiel helfen Compiler-Warnings nichts. Es sind (laut dem Artikel) weniger die unterschiedlichen Typen, die durch die ungarische Notation gekennzeichnet sind, als dieselben Typen mit unterschiedlicer Bedeutung.
    Häufiges Problem sind unterschiedliche Indizes auf Arrays (Vektoren o.ä.), die nicht austauschbar (d.h. zuweisbar) sind. Da Indizes gewöhnlich unsigned Typen sind, gibt es bei einer Zuweisung keine Warnung. Durch die Nutzung von "vernünftigen" Bezeichnern kann man solche Fehler erkennen.
    Gerne gesehen sind in Formeln auch falsche Einheiten:

    double s1 = 1000; // das soll meter (m) sein
      double s2 = 2;  // das soll Kilometer (km) sein
      double t = 10;  // sekunden (s)
      double v = (s1 + s2) / t;  // m/s
    

    Kein Compiler warnt Dich da. Bei solchen Sachen sind Kennzeichner nützlich (ich nutze hier immer eine Postfix Notation):

    double s1_m = 1000; 
      double s2_km = 2;  
      double t_s = 10; 
      double v_ms = (s1_m + s2_km) / t_s;
    

    Das hilft zumindest etwas. (Natürlich stehen die Zuweisung nicht einfach so da, sondern sind typischerweise wieder Berechnungsergebnisse von Funktionen, die einfach ein Double zurückgeben. Auch da verwendet ich dann bei den Funktionsnamen die physikalische Einheit in der Notation).

    Wenn ich den Artikel richtig verstanden habe, dann ist das wohl auch die Idee hinter der ungarischen Notation und nicht das ein double ein double ist und ein float ein float. Das zeigt sowieso eine vernünftige IDE einem an.



  • niemand schrieb:

    Gerne gesehen sind in Formeln auch falsche Einheiten:

    double s1 = 1000; // das soll meter (m) sein
      double s2 = 2;  // das soll Kilometer (km) sein
      double t = 10;  // sekunden (s)
      double v = (s1 + s2) / t;  // m/s
    

    Kein Compiler warnt Dich da. Bei solchen Sachen sind Kennzeichner nützlich (ich nutze hier immer eine Postfix Notation):

    ich nicht:

    http://www.awprofessional.com/articles/article.asp?p=375705&seqNum=1&rl=1

    Da warnt er nicht nur 🙂



  • Jester schrieb:

    ist ha großartig, daß man damit diese ganzen signed/unsigned-Fehler auf einen Blick sieht. Aber da ich auf Compiler-Warnungen großen Wert lege und mich mein Compiler bei sowas warnt sehe ich den Vorteil nicht.

    Ich achte ebenfalls strengstens auf Compiler-Warnings. In unserer Firma sind alle Sourcen zu 100% Warning-frei.

    Darum geht es aber garnicht.

    Ihre Aussage legt nahe, das Sie bei der Ungarischen Notation -wie schätzungsweise über 90% aller Programmierer- nicht an "Apps Hungarian" sondern an "Systems Hungarian" denken.

    Bei der Ungarischen Notation im Sinne ihres Erfinders geht es nicht um die Typ-Prüfung im eigentlichen Sinne (signed/unsigned,...). Sowas beherrscht natürlich jeder vernünftige Compiler.

    Der Prefix bei der ungarischen Notation soll eben gerade NICHT dazu benutzt werden etwas über den Datentyp auszusagen ("l" für long, "ul" für unsigned long,...) !!!

    Der Prefix bezeichnet die "Art der Daten" nicht den Datentyp.
    Genau darin liegt ja die Missinterpretation.

    Natürlich macht es KEINEN Sinn eine Integer Variable als "iFoo" zu bezeichnen. Das ist ja auch "Systems Hungarian", nicht "Apps Hungarian".

    Ich kann wirklich nur jedem empfehlen sich mal http://www.joelonsoftware.com/printerFriendly/articles/Wrong.html durchzulesen. Vor allem den Abschnitt "I'm Hungarian".



  • Aus dem Artikel schrieb:

    Simonyi’s original concept for Hungarian notation was called, inside Microsoft, Apps Hungarian, because it was used in the Applications Division, to wit, Word and Excel. In Excel’s source code you see a lot of rw and col and when you see those you know that they refer to rows and columns. Yep, they’re both integers, but it never makes sense to assign between them. In Word, I'm told, you see a lot of xl and xw, where xl means “horizontal coordinates relative to the layout” and xw means “horizontal coordinates relative to the window.” Both ints. Not interchangeable. In both apps you see a lot of cb meaning “count of bytes.” Yep, it’s an int again, but you know so much more about it just by looking at the variable name. It’s a count of bytes: a buffer size. And if you see xl = cb, well, blow the Bad Code Whistle, that is obviously wrong code, because even though xl and cb are both integers, it’s completely crazy to set a horizontal offset in pixels to a count of bytes.



  • Nutzt Du das für rechenintensive Methoden? Ist das genauso schnell, wie die das Rechnen mit nativen Typen? (Im Prinzip will man das ja genau erreichen, dass zur Compilezeit ein Fehler gemeldet wird und zur Laufzeit keine Penalty existiert. Ich kann das zumindest auf die Schnelle nicht erkennen). Andere Systeme (die typischerweise Klassen implementieren) sind deutlich langsamer.

    Ein zweites Problem ist: Bei einigen (wenigen) Millionen Zeilen Code innerhalb derer Du Routinen erweitern und ergänzen darfst und in dem ein solches System nicht existiert, bist Du dankbar, wenn wenigstens eine Kennzeichnung existiert, was die Methode/Funktion liefert.

    Was eigentlich für sowas gebraucht wird, ist ein typedef, dass nicht Zuweisungen anderer Typen ohne expliziten Cast verbietet.

    (Wir haben hier sowas zur Debugzeit mal probiert, indem wir über templates Klassen definiert haben, die sich wie doubles verhielten, aber Zuweisungen untereinander nicht erlaubten. Nach dem der Compiler den Code geschluckt hat, haben wir die Klassen wieder entfernt und daraus ein double gemacht.)



  • Hi,

    dieses "Apps Hungarian" ist doch auch nix anderes, als seine Variablen
    vernünftig zu benennen. Ob ich das jetzt als Prefeix oder sonstwie mache,
    ist doch Wurst.

    Jockel



  • niemand schrieb:

    Nutzt Du das für rechenintensive Methoden? Ist das genauso schnell, wie die das Rechnen mit nativen Typen? (Im Prinzip will man das ja genau erreichen, dass zur Compilezeit ein Fehler gemeldet wird und zur Laufzeit keine Penalty existiert. Ich kann das zumindest auf die Schnelle nicht erkennen). Andere Systeme (die typischerweise Klassen implementieren) sind deutlich langsamer.

    Ich hab das noch nicht für was rechenintensives benutzt. Aber ich hab mir die Implementierung angeschaut. Ein ordentlicher Optimierer kann alles wegwerfen bis auf die eigentlichen Rechenoperationen. Zur Compilezeit werden nur einige Typen verglichen. Und die müssen identisch sein, sonst gibt es nen Compiler-Fehler. Zur Laufzeit bleibt davon aber nix übrig.



  • Jockelx schrieb:

    Hi,
    dieses "Apps Hungarian" ist doch auch nix anderes, als seine Variablen
    vernünftig zu benennen.
    Jockel

    Es ist mehr. So richtig rund wird die Sache erst wenn man es auch auf Methodennamen ausweitet. Ist im Artikel perfekt beschrieben.

    Jockelx schrieb:

    Ob ich das jetzt als Prefeix oder sonstwie mache,
    ist doch Wurst.

    Da haben Sie im Prinzip schon recht. Das wichtigste ist, das am Ende dann auch gut lesbarer Sourcecode rauskommt. Was für eine Konvention verwenden Sie denn?



  • unfan schrieb:

    Was für eine Konvention verwenden Sie denn?

    Im Forum halte ich mich an die Konvention, die Leute mit 'du' anzusprechen 😉
    Ansonsten muss ich sowas nehmen, was in deinem Artikel als "Sys Hungarian"
    beschrieben wird. Finde ich mittlerweile aber auch ganz okay.

    Jockel



  • Der Artikel identifiziert das Problem, kommt aber meiner Meinung nach zur falschen Lösung. Sich an Namen aufzuhängen ist einfach zu fehleranfällig und sollte dem Compiler überlassen werden.

    Warum nicht direkt zwei Typen benutzen:

    SecureString
    String

    Und dann die Operatoren so einrichten:

    String blabla = "Evil hacker code";
    SecureString blub = "Teletubbie land";
    
    blabla = blub;   // Funktioniert einwandfrei
    blub = blabla;   // Compilererror
    blub = convert_to_secure_string(blabla); // kein Problem
    

    Man muss sich genauso wie bei der ungarischen Notation daran halten das zu benutzen. Aber sobald man die Eingabe des Users in einem String gespeichert hat, wird einen der Compiler solange in den Arsch treten, solange es noch irgendwo falsch benutzt wird. So ähnlich macht er das ja auch bei const.



  • Jockelx schrieb:

    Im Forum halte ich mich an die Konvention, die Leute mit 'du' anzusprechen ;-)Jockel

    Sorry, das "Sie" ist Berufsbedingt und sitzt mir mittlerweile irgendwie im Blut. 🙂



  • Hat eigentlich einer von euch den joelonsoftware Artikel gelesen? Da geht es doch darum, was die ungarische Notation wirklich bedeutet.

    Es geht darum, dass man nicht den Typ auszeichnet, sondern die Funktion der Variable. Zum Beispiel colFoo, damit man weiß, dass Foo ein Column ist. So kann man colFoo von rowBar unterscheiden und sieht eben, dass es ein Fehler ist, wenn man einem column eine row zuweist.

    Naja, man kann eben darüber streiten, ob es aus OO Sicht nicht eh verschiedene Typen für Column und Row geben sollte 😉



  • kingruedi schrieb:

    Hat eigentlich einer von euch den joelonsoftware Artikel gelesen?

    Da du scheinbar der einzige bist kannst Du vielleicht auch gleich noch erklären, warum wir alle das Thema verfehlen wenn wir sagen, daß der Compiler das besser kann. 🙄



  • unfan schrieb:

    Ich achte ebenfalls strengstens auf Compiler-Warnings. In unserer Firma sind alle Sourcen zu 100% Warning-frei.

    Das kann doch nur bedeuten, dass ihr nicht alle Warnungen eingeschaltet habt.
    Beim gcc muss man nur -Weffc++ und -Winline angeben, dann hat meiner Meinung nach jeder nichttriviale Code Warnungen, die man nicht beheben will.



  • Hallo

    Ich achte ebenfalls strengstens auf Compiler-Warnings. In unserer Firma sind alle Sourcen zu 100% Warning-frei.

    Dann ist SICHER die Warnstufe nicht auf alle gestellt ,
    denn sonst haettet ihr 100erte Warnings (sicher)

    Es sei denn ihr verzichtet auf alles (zB VCL....)
    und schreibt reinen API-Code (selbst dann ist es eher unwarscheinlich)

    MfG
    Klaus


Anmelden zum Antworten