Ungarische Notation veraltet



  • wisser schrieb:

    Die ungarische Notation kannst du meines Wissens komplett vergessen.

    Das sehe ich auch so.



  • hehejo schrieb:

    Ich bin auch von der Ungarischen Notation abgekommen.
    A) Sind meine Funktionen überschaubar kurz
    😎 Nutze ich sprechende Variablennamen: Also z.B. AngestellterName statt m_wspzAname
    C) Hab ich keine Probleme wenn sich der Typ meiner Variablen ändert. Gut mit passenden Refactoringmthoden kann ich schnell alle m_wspzAname in m_wspAname umändern - aber ich denke ihr wisst was ich meine.

    zu A): Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch :))
    zu B): wie du unter A) siehst, funktioniert das auch mit Variablen, welche einen kleinen Typen-Präfix haben.
    zu C): An sich hast du recht, man muss es überall ersetzen. Andererseits muss man in den meisten Fällen ohnehin den Code ändern, damit dieser mit dem neuen Typ funktioniert. Bei deinem Beispiel '_wspzAname' nach 'm_wspAname' gehe ich mal davon aus, dass du ein wchar_t* von einem nullterminierten String in einen nicht-nullterminierten String änderst. In dem Fall würden sämtliche Funktionen, welche die Nullterminierung erfordern, Probleme verursachen.
    Ansonsten bieten die meisten IDEs inzwischen gute Suchen&Ersetzen-Funktionen an.

    Chris++ schrieb:

    Na was ist denn nun der Unterschied zwischen lptstrAngestellterName und AngestellterName? Der Mehrwert an nützlichen Infos hält sich doch arg in Grenzen ( = 0). Und ob eine Nullterminierte Zeichenkette erwartet wird kann man doch eigentlich auch am Aufbau der Funktion erkennen.

    void Foo::SetzeName(char* AngestellterName) //kann ja nur Nullterminierte Zeichenkette erwarten, wie sollte man sonst das Ende der Zeichenkette erkennen?
    {
    }
    
    void Foo::SetzeName(char* AngestellterName, int Laenge) //Länge der Zeichenkette mit übergeben -> Nullterminierung nicht unbedingt notwendig
    {
    }
    

    Vieleicht irre ich mich auch und die Logik ,die ich hinter dem obigen Code sehe, ist total falsch. Bitte flame't mich dann zu.

    EDIT: Rechtschreibung++

    Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.



  • Suchen und Ersetzen widerlegt jeglichen Sinn der Typkodierung in den Variablennamen, aber nur so am Rande.

    Leute die den Typ in den Variablennamen einkodieren haben den Sinn von OOP oder generischer Programmierung nicht verstanden.



  • Das Thema interessiert mich schon lange und anscheinend sind hier viele Profis unterwegs. Folgendes Beispiel:

    CString CStringName;
    BSTR BSTRName;
    MyCOMObject->get_Name(&BSTRName);
    CStringName = (LPCTSTR)BSTRName;
    

    Wie markiert ihr gleiche Variablen mit unterschiedlichen Typen? Vor allem bei String, da es dort unzählige Varianten gibt. 😕



  • CString getName()
    {
        BSTR name;
        MyCOMObject->get_Name(&name);
        return (LPCTSTR)name;
    }
    


  • Oben ging es um die Variable einer Klasse, wodurch der Typ idR nur noch in der Header-Datei erkennbar ist. "AngestellterName" ist nun in sofern mehrdeutig, dass es ein char*, ein wchar_t*, std::string oder auch eine eigene Stringklasse sein kann.

    Wo ist da der Unterschied ?

    std::string AngestellerNameA = "Mayer";
    char* AngestellerNameB = "Mayer";
    wchar_t* AngestellerNameC = "Mayer";
    

    Wo ist da ein Unterschied ?
    Anderes Beispiel:

    int counterA = 0;
    long counterB = 0;
    float counterC = 0;
    
    ...
    counterA++;
    counterC++;
    counterD++;
    

    Wo ist da ein Unterschied ?

    Beispiel mit Klassen/Struct:

    struct LiedA
    {
          std::string album;
          std::string titel;
    
          LiedA(std::string album, std::string titel)
          {
              this->album = album;
              this->titel = titel;
          }
    
          std::string getAlbum() { return album; }
          std::string getTitel() { return titel; }
    }
    
    class LiedB
    {
        public:
          std::string album;
          std::string titel;
    
          LiedB(std::string album, std::string titel)
          {
              this->album = album;
              this->titel = titel;
          }
    
          std::string getAlbum() { return album; }
          std::string getTitel() { return titel; }
    }
    

    Wozu muss ich jetzt wissen ob Lied eine Klasse oder Struktur ist ?

    Funktionen können auch so überschaubar kurz sein - du musst ja nicht solch umständliche Präfixe wie 'm_wspz' wählen, was ich persönlich für viel zu lang halte. Bei mir hieße 'm_wspzAname' beispielsweise 'wName' (sofern sich die Klasse nur um den Angestellten dreht), ansonsten 'wEmployeeName' (ich bevorzuge Englisch )

    Jetzt muss ich also mir nicht nur den Namen der Variable sondern auch ihren Type merken?
    Statt einzutippen "coun" und die Autovervollständigung macht mir counterFürAlles,
    muss ich
    i_coun -> hmm da kommt nix
    s_coun -> hmm da kommt auch nix
    w_coun -> hmm da kommt wieder nix, welchen Type habe ich den gemacht ??
    u_coun -> ahh endlich -> u_counterFürAlles

    Was ich damit sagen will: Ich will den Typen überhaupt nicht wissen. Wenn etwas falsch ist, dann meldet der Compiler! ein Fehler oder eine Warnung. Dafür ist der Compiler da. In C++ gibt es nicht umsonst Operatorüberladung damit Klassen sich wie Buildin-Typen anfühlen. Das ist eben einer der Vorteile von OOP-Sprachen wie C++, Java, C#, Ruby, usw.



  • DEvent schrieb:

    int counterA = 0;
    long counterB = 0;
    float counterC = 0;
    
    ...
    counterA++;
    counterC++;
    counterD++;
    

    Wo ist da ein Unterschied ?

    Das ist einfach:

    [cpp]
    int counterA = 0;
    long counterB = 0;
    float counterC = 0;

    ...
    counterA++;
    counterC++;
    counterD++;[/cpp]

    SCNR 😃 😉

    @electron, wenn du das nicht öfter machen musst, dann könnte man eine Funktion dafür auch weglassen und die Variablen einfach passend bennenen:

    CString name;
    BSTR tempName;
    MyCOMObject->get_Name(&tempName);
    name = (LPCTSTR)tempName;
    

    Jetzt ist sofort ersichtlich, dass BSTR nur dazu verwendet wird um den Namen zwischenzuspeichern und nach diesem Codeblock keine weitere Rolle mehr spielt.

    Aber eine Funktion wie von :o vorgeschlagen ist natürlich zu Bevorzugen, wenn du das des öfteren machst.



  • Ergänzung:
    Noch besser ist es natürlich sich strikt an RAII zu halten und das ganze zu folgendem zu vereinfachen:

    BSTR tempName;
    MyCOMObject->get_Name(&tempName);
    CString name = (LPCTSTR)tempName;
    

    Aber all das hat man bei der Funktion von :o bereits, besser kann man es nicht machen.



  • DEvent schrieb:

    std::string AngestellerNameA = "Mayer";
    char* AngestellerNameB = "Mayer";
    wchar_t* AngestellerNameC = "Mayer";
    

    Wo ist da ein Unterschied ?

    Die Definiton ist gleich, aber die Verwendung nicht.
    Beispiel:

    if (AngestellerNameA1 == AngestellerNameA2) // gut
       ...;
    
    if (AngestellerNameB1 == AngestellerNameB2) // schlecht
       ...;
    
    if (AngestellerNameC1 == AngestellerNameC2) // schlecht
       ...;
    


  • Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
    gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
    von Anfang an ne schwachsinnige Idee...

    G,S



  • Sprengsatz schrieb:

    Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
    gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
    von Anfang an ne schwachsinnige Idee...

    G,S

    Amen.

    MfG, total normal



  • Sprengsatz schrieb:

    Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
    gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
    von Anfang an ne schwachsinnige Idee...

    G,S

    Amen.

    MfG, full ack



  • full ack schrieb:

    Sprengsatz schrieb:

    Die ungarische Notation ist die taktische Nuklearwaffe im Kampf
    gegen lesbaren Code - veraltet ist das falsche Wort, das war schon
    von Anfang an ne schwachsinnige Idee...

    G,S

    Amen.

    MfG, full ack

    Ich wusste garnicht, dass es auch virtuelle Schatten wie dich gibt!

    MfG, total normal



  • :o schrieb:

    CString getName()
    {
        BSTR name;
        MyCOMObject->get_Name(&name);
        return (LPCTSTR)name;
    }
    

    Dr. Prof schrieb:

    Ergänzung:
    Noch besser ist es natürlich sich strikt an RAII zu halten und das ganze zu folgendem zu vereinfachen:

    BSTR tempName;
    MyCOMObject->get_Name(&tempName);
    CString name = (LPCTSTR)tempName;
    

    Aber all das hat man bei der Funktion von :o bereits, besser kann man es nicht machen.

    Das diese Funktion eine Speicherleiche produziert ist euch hoffentlich klar. 🙄 🙄


  • Administrator

    Also auch auf die Gefahr hin, dass ich verkloppt werde, ich bin FÜR die ungarische Notation. Ich kann sie leider immer noch nicht zu 100%, da ich ein paar seltene Typen oft wieder vergesse, aber ansonsten probiere ich sie so oft wie möglich anzuwenden. Wieso?

    1. Lesbarkeit. Genau das, wo so viele sagen, dass es nicht gefördert wird. Also ich weiss nicht aber ich kann einen Code der mit der ungarischen Notation versehen ist, deutlich schneller lesen und verstehen, als einer ohne. Wenn viele Variablen am Anfang einer grösseren Funktion deklariert werden oder in eine Klasse usw. dann kann ich mir nicht auswendig merken von welchem Typ jede Variable ist. Und ich will nicht immer mit der Maus über die Variable gehen, während dem Lesen um zu schauen von welchem Typ die ist.

    2. Kürzere Variablen.

    int nNamen;
    

    Ist für mich klar, eine Anzahl Namen

    int NamenCount;
    

    Muss es mindestens ohne Notation heissen, denn unter Namen könnte man auch alles andere verstehen. Vielleicht eine Liste? Oder ein string mit Namen drin?

    3. Variablennamen doppelt verwenden und trotzdem Klarheit. Zudem werden sie auch wie in 2. kürzer.

    int nFirstAssist;
    

    Nummer des FirstAssist Spielers.

    CString strFirstAssist;
    

    Name des FirstAssist Spielers.

    4. Ich kann auch Quellcode als Text verschicken und darin ist dann auch noch klar, als was die Namen gemeint sind. Gerade für eine Dokumentation zu einem Quellcode, denke ich ist dies sehr angenehm.

    5. Und ich wage nun sogar was ganz gemeines zu behaupten, damit man mich auch brav stark auseinander nimmt, ihr seid doch nur zu faul um die ungarische Notation zu lernen. Denn die Beispiele, welche hier teilweise aufgelistet wurden, waren manchmal sowas von schön. Klassen ohne Unterscheidung von privat, protected und public und so vereinfacht, wie wohl nie irgend eine Klasse aussehen wird. Klar sieht sie dann gleich aus wie eine Struktur und man fragt sich dann wieso sollte man nun ein C für Klassen verwenden und z.b. ein S für Strukturen. Die Sache ist aber die, dass halt Klassen oft komplexer sind und z.b. mehr Funktionen und solches Zeug anbieten, während eine Struktur oft nur eine Auflistung von verschiedenen Variablen ist ganz ohne Funktionen. Zudem ist es dann auch angenehmer und schneller zum unterscheiden zwischen Objekttyp und Variable.

    Grüssli und viel Spass



  • Ich hab jetzt die letzten Seiten nur überflogen, doch ich glaube hier liegt ein grundlegendes Missverständnis in Sachen Ungarische Notation vor.
    Die ursprüngliche Version der Hungarian Notation, die sog. Apps Hungarian wurde dafür entwickelt um eine Aussage über die Funktion der Variable zu machen und nicht über den Typen.
    Die zweite Version, die auch in diesem Thread herumgeistert ist das Systems Hungarian, wo nur eine Aussage über den Datantypen mittels Präfix getroffen wird (manchmal zusätzliches noch ein Präfix für die Sichtbarkeit/static).
    Ich weiß das, weil ich zufälligerweise vor kurzem ein Referat derüber in Softwareengingeering gehalten habe. Hier die Präsentation dazu:

    www.project101.de/other/UngarischeNotation.pdf



  • Ich kann sie leider immer noch nicht zu 100%

    Ähm, was gibt es da eigentlich groß zu lernen? 10min ne Tabelle (o.ä.) überfliegen und dann anwenden, das is kein Prozess von Wochen.

    5. Und ich wage nun sogar was ganz gemeines zu behaupten, damit man mich auch brav stark auseinander nimmt, ihr seid doch nur zu faul um die ungarische Notation zu lernen.

    Und ich behaupte das Gegenteil 🙂
    Hab früher (Anfangszeiten) auch HN benutzt, aber einfach aus dem Grund heraus, weil ich zu FAUL war und es mir zu schwer viel mir RICHTIGE Namen für meine Valiablen auszudenken.

    Wenn du in C++ mit Klassen arbeitest, gibtst du den Objekten dann auch Präfixe, oder einen passenden Namen? 😕



  • pZy schrieb:

    Hab früher (Anfangszeiten) auch HN benutzt, aber einfach aus dem Grund heraus, weil ich zu FAUL war und es mir zu schwer viel mir RICHTIGE Namen für meine Valiablen auszudenken.

    War bei mir auch so. Das habe ich mir dann aber abgewöhnt als mir nBuffer (für was???), m_sedtStartNr (oha...) zuviel wurde. Ausserdem sehe ich keinen Unterschied bzw. Vorteil der UN im nachfolgenden Code.

    //UN
    if(bErgebnislisteGeladen)
    //ohne UN
    if(ErgebnislisteGeladen)
    

    Jetzt mal im Ernst... Wo ist hier der Nutzen von "b..." und in welchem Fall ist das b gerechtfertigt? Ich sehe hier keinen (sinnvollen) Unterschied, ausser das das b... den Lesefluss stört. Da müsst ihr mir doch zustimmen oder?


  • Administrator

    pZy schrieb:

    Ich kann sie leider immer noch nicht zu 100%

    Ähm, was gibt es da eigentlich groß zu lernen? 10min ne Tabelle (o.ä.) überfliegen und dann anwenden, das is kein Prozess von Wochen.

    Ich habe aber noch dazugefügt, wegen den Dingen, die ich eben nicht so oft benutze. Zum Beispiel brauche nicht nicht so oft das char und ganz ehrlich, ich benutze es so wenig ich weiss es derzeit nicht einmal. Aber ich meine es ist ch oder c, aber kann mich eben nicht so entscheiden ^^

    Zudem gibt es das Problem, dass Microsoft ihre eigene ungarische Notation gemacht hat und diese fliesst ständig auf mich ein, weil ich oft mit der MFC programmiere. Dadurch habe ich ein wenig ein mischmasch zwischen der von Windows und der eigentlichen Notation. Deshalb sag ich, dass ich sie nicht zu 100% kann. Aber irgendwann mal muss ich mir endlich eine einzige angewöhnen. Vor allem, wenn es bei mir mal wirklich professionell werden sollte 😉

    pZy schrieb:

    5. Und ich wage nun sogar was ganz gemeines zu behaupten, damit man mich auch brav stark auseinander nimmt, ihr seid doch nur zu faul um die ungarische Notation zu lernen.

    Und ich behaupte das Gegenteil 🙂
    Hab früher (Anfangszeiten) auch HN benutzt, aber einfach aus dem Grund heraus, weil ich zu FAUL war und es mir zu schwer viel mir RICHTIGE Namen für meine Valiablen auszudenken.

    Ich benutze beides, bzw. verbinde die zwei Dinge, wodurch es eben erst so wirksam wird!

    pZy schrieb:

    Wenn du in C++ mit Klassen arbeitest, gibtst du den Objekten dann auch Präfixe, oder einen passenden Namen? 😕

    Ja und nein. Das ja wegen dem p bei Zeigern oder ref bei einer Referenz. Aber ansonsten nein, dann heisst es eben:

    CTeam Team;
    /* oder */
    CPlayer Player;
    

    Allerdings in einer Klasse heisst es dann wiederrum

    class CIrgendwas
    {
        // ...
        CTeam m_Team;
        /* oder */
        CPlayer* m_pPlayer;
        /* oder manchmal sogar */
        CTeam m_TeamIrgendwas;
        // ...
    }
    

    Die ungarische Notation behandelt aber dies, soweit ich weiss, gar nicht. Bei dieser geht es nur um die Grundtypen, also Zeiger, Referenzen, Integer, Float, Double, Long, Strings usw.

    In der Vorschau noch grad gesehen:
    @Chris++
    Jo es werden dir 90% der Leute zustimmen, da kannst dir sicher sein. Aber ich nicht. ErgebnislisteGeladen könnte auch ein Integer sein, denn if(5) if(10) usw. geht auch und wird auch als true angesehen. Wieso es eine Zahl sein könnte? Tjo, vielleicht willst damit sagen, wieviele Ergebnislisten geladen wurden. Das b stört den Lesefluss auf keinen fall, nein es sagt mir sofort, ach das ist ein bool wert, also nur 1 oder 0. Das kann somit nur darum gehen ob die Ergebnisliste bereits geladen wurde oder nicht. Man kommt gar nicht auf die Idee, dass es etwas anderes sein könnte, denn es wird simpel einfach ausgeschlossen.

    Grüssli



  • Dravere schrieb:

    @Chris++
    Jo es werden dir 90% der Leute zustimmen, da kannst dir sicher sein. Aber ich nicht. ErgebnislisteGeladen könnte auch ein Integer sein, denn if(5) if(10) usw. geht auch und wird auch als true angesehen. Wieso es eine Zahl sein könnte? Tjo, vielleicht willst damit sagen, wieviele Ergebnislisten geladen wurden. Das b stört den Lesefluss auf keinen fall, nein es sagt mir sofort, ach das ist ein bool wert, also nur 1 oder 0. Das kann somit nur darum gehen ob die Ergebnisliste bereits geladen wurde oder nicht. Man kommt gar nicht auf die Idee, dass es etwas anderes sein könnte, denn es wird simpel einfach ausgeschlossen.

    Gutes Argument. Aber ich denke das dein Beispiel auch vom Programmierstil abhängig ist. Ich würde jetzt z.B. für ErgebnislisteGeladen nur dann einen Intwert vereinbaren wenn ich damit verschiedene Zustände darstellen will (und für diese konstanten defniert habe):

    Class Ergebnisliste
    {
    public:
       int HoleLadeZustand();
       enum LadeZustaende
       {
           nichtGeladen = 0,
           teilweiseGeladen = 1,
           vollstaendigGeladen = 2,
       }
       //anderes zeugs...
    }
    
    //Abfrage sähe dann (bei mir) in etwa so aus
    int ErgebnislisteGeladen = ergebnisliste.HoleLadeZustand();
    
    if(ErgebnislisteGeladen == Ergebnisliste::vollstaendigGeladen)
    //...
    

    Also ich persönlich würde einen Intwert wirklich nur dann nehmen, wenn ich unterschiedliche Zustände verarbeiten muss (also wie das BOOL in der MFC). Hab ich mir so angewöhnt.

    EDIT: Ich muss aber auch zugeben das ich lange über den Sinn von

    typedef int                 BOOL;
    

    nachgedacht habe 😃


Anmelden zum Antworten