Ungarische Notation veraltet



  • Also mit der IDE hat die HN nichts zu tun, sondern viel mehr mit der eingesetzten Programmiersprache.

    In C mag man es noch verstehen, aber C++ hat ist eine objektorientierte typensiche Sprache. Da hat HN nichts mehr zu suchen.
    Die wird meist nur noch verwendet weil ein Entwickler zu faul ist sich ordentliche Namen für seine Variablen auszudenken (mit ein wenig Überung ist das kein Problem mehr).

    Wer den Mumm hat sich das mal anzusehen:

    http://www.ddj.com/dept/cpp/184403804

    Herb Sutter sollte man auf alle Fälle ernst nehmen 🙂
    Vielleicht öffnet es machen ja die Augen.
    MS selbst rät in .NET von der HN sowieso ab.

    "Avoid Hungarian notation. It will make a liar out of you.
    Warts are not information, but disinformation."

    WM_CHEERS



  • Ich finde die ungarische Notation auch ziemlich überflüssig. Ein Source sollte sich lesen wie ein "normaler" Text. Dh, es sollte eigentlich aus dem Kontext klar werden, welchen Typ eine Variable hat. Sinnvolle Namensgebung ist wichtiger, auch weil dadurch Verwendung und Bedeutung ersichtlich sind.



  • Lasst die Variablen doch jeden seine so nennen, wie er am besten damit zurecht kommt. Kritisch wird es erst, wenn man mit mehreren Personen an einem Projekt arbeitet - dann sollte man sich auf eine Schreibweise einigen.

    Ich habe auch total chaotisch angefangen mit den Bezeichnungen, aber mit jedem Projekt habe ich meine Schreibweise verbessert, so dass ich jedes Mal besser damit zurecht kam - und darauf kommt es eben erstmal an.

    Inzwischen sieht das so aus:

    Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.

    Präfixe für Variablenbezeichner:
    b: bool
    c: char/char*
    h: Funktionszeiger (Callbacks)
    o: Objekte (Typ wird aus dem Namen klar, ansonsten wäre auch der Präfix zu lang)
    s: sint8/sint16/sint32/sint64 (ganzzahlig, mit Vorzeichen)
    u: uint8/uint16/uint32/uint64 (ganzzahlig, ohne Vorzeichen)
    v: void*
    w: wchar_t/wchar_t*

    Typbezeichner bestehen aus einem Präfix (Großbuchstaben) für die Art des Typs, gefolgt vom Namen.

    Präfixe für Typbezeichner:
    S: struct (SBlubb, SBla, SWasAuchImmer)
    C: class (CBlubb, CBla, CWasAuchImmer)
    T: für spezielle Typedefs (TSize, TOffset, TPosition - jeweils Systemabhängig, ähnlich wie size_t)

    Statische Variablen haben vor dem Präfix noch ein '_' (wobei ich noch nicht weiß, ob das Probleme verursachen kann. Eine bessere Lösung habe ich hier noch nicht.).

    Auf Membervariablen der aktuellen Klasse wird explizit per 'this->' zugegriffen.

    [edit]Inzwischen habe ich mir auch vorgeschrieben, Bezeichner nicht mehr abzukürzen (uPosition statt uPos, sOffset statt sOff, uLength statt uLen, etc.), seien die Bezeichner auch noch so lang. Die Abkürzungen waren vor IntelliSense schneller zu schreiben, aber dafür war der Code schwerer zu lesen.[/edit]

    Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.



  • Neku schrieb:

    Lasst die Variablen doch jeden seine so nennen, wie er am besten damit zurecht kommt. Kritisch wird es erst, wenn man mit mehreren Personen an einem Projekt arbeitet - dann sollte man sich auf eine Schreibweise einigen.

    Ich habe auch total chaotisch angefangen mit den Bezeichnungen, aber mit jedem Projekt habe ich meine Schreibweise verbessert, so dass ich jedes Mal besser damit zurecht kam - und darauf kommt es eben erstmal an.

    Inzwischen sieht das so aus:

    Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.

    Präfixe für Variablenbezeichner:
    b: bool
    c: char/char*
    h: Funktionszeiger (Callbacks)
    o: Objekte (Typ wird aus dem Namen klar, ansonsten wäre auch der Präfix zu lang)
    s: sint8/sint16/sint32/sint64 (ganzzahlig, mit Vorzeichen)
    u: uint8/uint16/uint32/uint64 (ganzzahlig, ohne Vorzeichen)
    v: void*
    w: wchar_t/wchar_t*

    Typbezeichner bestehen aus einem Präfix (Großbuchstaben) für die Art des Typs, gefolgt vom Namen.

    Präfixe für Typbezeichner:
    S: struct (SBlubb, SBla, SWasAuchImmer)
    C: class (CBlubb, CBla, CWasAuchImmer)
    T: für spezielle Typedefs (TSize, TOffset, TPosition - jeweils Systemabhängig, ähnlich wie size_t)

    Statische Variablen haben vor dem Präfix noch ein '_' (wobei ich noch nicht weiß, ob das Probleme verursachen kann. Eine bessere Lösung habe ich hier noch nicht.).

    Auf Membervariablen der aktuellen Klasse wird explizit per 'this->' zugegriffen.

    [edit]Inzwischen habe ich mir auch vorgeschrieben, Bezeichner nicht mehr abzukürzen (uPosition statt uPos, sOffset statt sOff, uLength statt uLen, etc.), seien die Bezeichner auch noch so lang. Die Abkürzungen waren vor IntelliSense schneller zu schreiben, aber dafür war der Code schwerer zu lesen.[/edit]

    Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.

    Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...



  • Ein ganz kurzer schrieb:

    Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...

    Ich gebe zu, die Beispiele waren nicht die besten 🤡



  • Neku schrieb:

    Ein ganz kurzer schrieb:

    Auschreiben. pffff. Ich kürze zB buffer IMMER mit buf ab. Dann hab ich keine probleme zu lesen. Okay Offset kling besser wie Off, weil Off nciht iendeutig ist. Aber bei Len weiß doch jeder, dass length gemeint ist...

    Ich gebe zu, die Beispiele waren nicht die besten 🤡

    Na dann ist ja gut.



  • Neku schrieb:

    Variablenbezeichner bestehen aus aus einem Präfix (Kleinbuchstaben) abhängig vom Typ und dem Namen. Die Präfixe stehen nur für den Basistyp und sind unabhängig von Indirektionen (Pointer, Referenzen) oder 'const'.

    Was bringt es dir dann? du bist am ende genauso klug wie jemand der keine prefixe verwendet...

    schlimmer noch:

    cFoo
    soll ein zeiger sein? aua aua aua.

    Ob andere damit klar kommen ist unwichtig, solange ohnehin nur ich an dem Projekt arbeite.

    das ist imho die falsche einstellung...

    PS:
    naja, schon komisch was manche leute fuer vorlieben haben... da lob ich mir ehrlich gesagt typenlose sprachen, da kommen die leute nicht auf so komische ideen...
    oder java 😉 fuer all seine fehler, wenigstens kommt dort keiner auf die idee ungarisch zu verwenden... immer diese C altlasten 😞



  • Neku schrieb:

    c: char/char*
    v: void*
    w: wchar_t/wchar_t*

    zwischen pointern und nicht-pointern machste keinen unterschied? das ist schlecht.



  • Das unterscheidet halt die C+- und von den C++-Programmierern..



  • net schrieb:

    Neku schrieb:

    c: char/char*
    v: void*
    w: wchar_t/wchar_t*

    zwischen pointern und nicht-pointern machste keinen unterschied? das ist schlecht.

    Bei void sollte der Fall klar sein 😃
    char und wchar_t werden nur sehr sehr selten benutzt, da ich für Strings idR eine Stringklasse verwende. Sollten dennoch char oder wchar_t auftauchen, so wird aus dem Variablen klar, was gemeint ist (z.B. wCharacter).

    @Shade Of Mine: Bei typenlosen Sprachen dürfte es sogar noch wichtiger sein, Präfixe abhängig des Typs zu verwenden, denn dort weist einen der Compiler nicht auf Probleme hin. Angenommen du verwendest irgendwo eine Variable als String und anderswo aus versehen als bool in einer Bedingung (noch besser in PHP: ein Array als Boolean :))
    Und erklär doch mal, warum das "die falsche einstellung" ist, wenn ich der einzige bin, der den Code je zu sehen bekommt.
    Von C kommt das bei mir übrigens nicht. Ich habe direkt mit C++ angefangen und auch erst Variablennamen ohne Typ-Präfix verwendet. Das endete generell im Chaos und so habe ich mir mit der Zeit eine hilfreiche Bezeichnerregelung geschaffen.

    Shade Of Mine schrieb:

    cFoo
    soll ein zeiger sein? aua aua aua.

    Da ich nur in schätzungsweise 0.1% meines Quellcodes Variablen vom Typ char habe liegt es nahe, einfach c für char* zu verwenden.



  • Neku schrieb:

    Bei typenlosen Sprachen dürfte es sogar noch wichtiger sein, Präfixe abhängig des Typs zu verwenden, denn dort weist einen der Compiler nicht auf Probleme hin.

    Bei typenlosen Sprachen kann eine Variable auch mal den Typ wechseln. Was hilft dir dann deine Ungarische Notation!?

    Greetz, Swordfish



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



  • Ich finde die ungarische Notation absolut nicht intuitiv.
    Ich weiß noch ganz genau, wie ich damals mit DirectX / WinApi angefangen habe, die ganzen Abkürzungen waren total nichtssagend und der Sinn blieb mir verschlossen.

    Hilft also nur, wenn man diese komische Notation bereits beherrscht.

    btw. C vor Klassennamen ist hässlich :p



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



  • Die ungarische Notation kannst du meines Wissens komplett vergessen.



  • 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;
    }
    

Anmelden zum Antworten