Dlaczego nie powinienem używać „notacji węgierskiej”?


122

Wiem, do czego odnosi się język węgierski - podając informacje o zmiennej, parametrze lub typie jako przedrostek do jej nazwy. Wydaje się, że wszyscy są temu wściekle przeciwni, chociaż w niektórych przypadkach wydaje się to dobrym pomysłem. Jeśli czuję, że przekazywane są przydatne informacje, dlaczego nie miałbym ich umieścić tam, gdzie są dostępne?

Zobacz także: Czy ludzie używają węgierskich konwencji nazewnictwa w prawdziwym świecie?


Odpowiedzi:


174

Większość ludzi używa notacji węgierskiej w niewłaściwy sposób i otrzymuje błędne wyniki.

Przeczytaj ten doskonały artykuł Joela Spolsky'ego: Sprawianie, że zły kod wygląda źle .

Krótko mówiąc, notacja węgierska, w której poprzedzasz nazwy zmiennych ich type(ciągiem) (węgierski systemowy) jest zła, ponieważ jest bezużyteczna.

Notacja węgierska zgodnie z zamierzeniami jej autora, w której przed nazwą zmiennej kind(na przykładzie Joela: bezpieczny ciąg znaków lub niebezpieczny ciąg znaków) przed nazwą zmiennej , tak zwany węgierski Apps ma swoje zastosowania i nadal jest cenny.


5
Dobry link, dobre podsumowanie tego, co kryje się za linkiem, bez fanatyzmu. Doskonały.
Dustman,

12
Zauważ, że przykład Joelsa jest w VBScript, języku, który od dawna nie miał klas zdefiniowanych przez użytkownika. W języku OO wystarczy utworzyć typ HtmlEncodedString i pozwolić, aby metoda Write akceptowała tylko to. „Węgierskie aplikacje” są przydatne tylko w językach bez typów zdefiniowanych przez użytkownika.
JacquesB

4
Firma Microsoft jest znana z nadużycia notacji węgierskiej w przeszłości. Dołączanie informacji o typie do identyfikatorów jest nie tylko bezużyteczne, ale może w rzeczywistości zaszkodzić. Po pierwsze, czytelność jest mniej płynna. Po drugie, w językach, które obsługują polimorfizm lub pisanie typu kaczego, przekazywane są nieprawidłowe informacje.
wilhelmtell

9
Nadal lubię używać notacji węgierskiej, jeśli robię proste programowanie w C ze starszym IDE ... w ten sposób wiem, że nie ma problemów z rzutowaniem typów.
Sygnał dźwiękowy

3
@Krumia: Zazwyczaj można by temu zapobiec, umieszczając opisowe nazwy zmiennych na pierwszym miejscu. Ale jeśli chcesz mieć pewność, znacznie bezpieczniej byłoby utworzyć odrębne typy (np. Struktury) dla długości, wag itp. I użyć przeciążenia operatorów, aby upewnić się, że możliwe są tylko prawidłowe operacje.
JacquesB

277

vUżywanie adnotacji węgierskiej vmakes nreading ncode adjdifficult.


101
Niezła analogia, choć trochę niesprawiedliwa. Porównaj: vUsing adj Węgierski nNotation vMake nCzytanie nCode adjTrudne.
Chris Noe,

27
W tym zdaniu zarówno używanie, jak i czytanie są odczasownikami. Ale rozumiem, o co ci chodziło ...
szympans

28
@chimp: dzięki temu rzeczy są jeszcze bardziej oczywiste. teraz, gdy znalazłeś błąd w typie, zamierzasz zmienić nazwy wszystkich odniesień lub pozostawić je bez zmian, podając błędne informacje? tak czy inaczej przegrywasz. ale oczywiście jest to NIEPRAWIDŁOWY sposób stosowania notacji węgierskiej.
wilhelmtell

1
@Chris Noe: w przypadku niektórych stylów czytania (przeanalizuj przedrostek i sufiks, rzucając okiem na środek), twój przykład tylko pogarsza sytuację. Widzę „vUsing” i słyszę „głos” w mojej głowie.
Bob Cross,

3
@Jon: jeśli masz nazwę zmiennej, która nie oddaje w pełni tego, co reprezentuje, to zdecydowanie należy skupić się na zmianie jej nazwy na bardziej opisową (a notacja węgierska nie jest poprawą w samym, bardzo W najlepszym przypadku jest to naprawienie objawu - a nie rozwiązanie problemu).
hlovdal

104

Joel się myli i oto dlaczego.

Informacje o „aplikacji”, o których mówi, powinny być zakodowane w systemie typów . Nie powinieneś polegać na odwracaniu nazw zmiennych, aby upewnić się, że nie przekazujesz niebezpiecznych danych do funkcji wymagających bezpiecznych danych. Powinieneś zrobić z tego błąd typu, aby nie można było tego zrobić. Wszelkie niebezpieczne dane powinny mieć typ oznaczony jako niebezpieczne, aby po prostu nie można ich było przekazać do funkcji bezpiecznej. Konwersja z niebezpiecznej do bezpiecznej powinna wymagać przetwarzania z jakąś funkcją dezynfekcji.

Wiele rzeczy, które Joel nazywa „rodzajami”, nie są rodzajami; w rzeczywistości są typami.

Jednak w większości języków brakuje systemu czcionek, który byłby wystarczająco wyrazisty, aby wymusić tego rodzaju rozróżnienia. Na przykład, jeśli C miałby rodzaj „silnego typedef” (gdzie nazwa typedef zawierałaby wszystkie operacje typu podstawowego, ale nie można jej było zamienić na niego), to wiele z tych problemów zniknęłoby. Na przykład, gdybyś mógł powiedzieć, że strong typedef std::string unsafe_string;aby wprowadzić nowy typ unsafe_string, którego nie można przekonwertować na std :: string (a więc może uczestniczyć w rozwiązywaniu przeciążeń itp.), Nie potrzebowalibyśmy głupich prefiksów.

Tak więc główne twierdzenie, że język węgierski dotyczy rzeczy, które nie są typami, jest błędne. Jest używany do informacji typu. Z pewnością bogatsze informacje typu niż tradycyjne informacje typu C; jest to informacja typu, która koduje jakiś semantyczny szczegół wskazujący przeznaczenie obiektów. Ale nadal jest to informacja o typie, a właściwym rozwiązaniem zawsze było zakodowanie ich w systemie typów. Zakodowanie go w systemie typów jest zdecydowanie najlepszym sposobem na uzyskanie właściwej walidacji i egzekwowania reguł. Nazwy zmiennych po prostu nie przecinają musztardy.

Innymi słowy, celem nie powinno być „sprawienie, by zły kod wyglądał źle dla programisty”. Powinno być „sprawić, by zły kod wyglądał źle dla kompilatora ”.


30
Zamiar zmiennej powinien być zakodowany w typie zmiennej, a nie pozostawiony czemuś tak delikatnemu jak cholerny schemat nazewnictwa.
DrPizza

3
Bardzo chciałbym, aby to również była praca kompilatora / interpretera, ale spowodowałoby to ogromne obciążenie dla języków dynamicznych (Python, Ruby, PHP lub Javascript).
za dużo php

22
„Jednak w większości języków brakuje systemu czcionek, który byłby wystarczająco wyrazisty, aby wymusić tego rodzaju rozróżnienia”. I w tym tkwi problem. AppsHungarian to pragmatyczna metoda zwracania uwagi programistów na problemy podczas używania tych języków w sposób oczywisty, zamiast sprawdzania raportów o błędach.
Neil Trodden

6
@DrPizza: Myślę, że przegapiłeś jedną z bardzo ważnych kwestii, które Joel poruszył, opowiadając się za Google Apps Hungarian: ta notacja jest po prostu bardzo pragmatycznym kompromisem . Sprawienie, by kompilator mógł zobaczyć „zły kod” to wspaniały cel, ale czy zawsze jest wart swojej ceny?
Yarik

4
@DrPizza: Joel is wrongi What most languages lack, however, is a type system that's expressive enough to enforce these kind of distinctions.tak, ponieważ większość języków nie brakuje wystarczająco wyrazistość do egzekwowania tego rodzaju wyróżnienia, Joel ma rację. Dobrze?
sampathsris,

46

Myślę, że to masowo zaśmieca kod źródłowy.

Nie daje też wiele korzyści w przypadku silnie pisanego języka. Jeśli zrobisz jakąkolwiek formę niezgodności typów i oszukanie, kompilator poinformuje Cię o tym.


Łał. 90 powtórzeń w 15 minut. Dobra decyzja.
Dustman,

2
Jeśli używasz go do pisania, to tak, jest bezużyteczny. Warto podać inne informacje.
Lou Franco,

12
@Lou, dokładnie - osobiście przechowuję historię wersji w moich nazwach zmiennych: string firstName_wasName_wasNameID_wasSweetCupinCakes
Shog9

@nsanders: Spróbuj użyć kompilatora, aby sprawdzić, czy użyto tych samych jednostek miary, gdy oba typy zmiennych są liczbami całkowitymi.
Igor Levicki

1
@ Shog9: Myślę, że nie zrozumiałeś węgierskiej notacji aplikacji. Chodzi bardziej o sFirstName vs unFirstName (bezpieczny vs niebezpieczny, niezanityzowany), dzięki czemu wiesz o tym coś więcej. Nadal uważam, że w językach statycznych lepiej jest podtyp String, aby utworzyć UnsafeString i SafeString i zezwolić tylko na wyjście SafeString. Konwencja jest w porządku, ale (częściej) egzekwowanie kompilacji jest lepsze.
kgadek

28

Notacja węgierska ma sens tylko w językach bez typów zdefiniowanych przez użytkownika . W nowoczesnym języku funkcjonalnym lub języku obiektowym zakodowałbyś informacje o „rodzaju” wartości w typie danych lub klasie, a nie w nazwie zmiennej.

Kilka odpowiedzi dotyczy artykułu Joelsa . Zauważ jednak, że jego przykład jest w języku VBScript, który nie obsługiwał klas zdefiniowanych przez użytkownika (przynajmniej przez długi czas). W języku z typami zdefiniowanymi przez użytkownika można rozwiązać ten sam problem, tworząc typ HtmlEncodedString, a następnie pozwalając metodzie Write zaakceptować tylko to. W języku z typowaniem statycznym kompilator wychwyci wszelkie błędy kodowania, w przypadku dynamicznego wpisania wystąpi wyjątek czasu wykonania - ale w każdym przypadku jesteś chroniony przed pisaniem niezakodowanych ciągów. Notacje węgierskie po prostu zamieniają programistę w człowieka sprawdzającego typ, a jest to rodzaj pracy, którą zwykle lepiej wykonuje oprogramowanie.

Joel rozróżnia „węgierski system” i „węgierski aplikacje”, gdzie „węgierski system” koduje wbudowane typy, takie jak int, float itp., A „węgierski aplikacje” koduje „rodzaje”, czyli meta-informacje wyższego poziomu o zmiennej poza typem maszyny, W OO lub nowoczesnym języku funkcjonalnym można tworzyć typy zdefiniowane przez użytkownika, więc nie ma rozróżnienia między typem a „rodzajem” w tym sensie - oba mogą być reprezentowane przez system typów - i „aplikacje” węgierski jest tak samo zbędny jak węgierski „systemowy”.

A więc odpowiadając na twoje pytanie: węgierski system byłby przydatny tylko w niebezpiecznym, słabo typizowanym języku, gdzie np. Przypisanie wartości zmiennoprzecinkowej do zmiennej int spowoduje awarię systemu. Notacja węgierska została specjalnie wynaleziona w latach sześćdziesiątych do użytku w BCPL , języku niskiego poziomu, który w ogóle nie sprawdzał typów. Nie sądzę, żeby jakikolwiek język w powszechnym użyciu miał dziś ten problem, ale notacja przetrwała jako rodzaj kultowego programowania cargo .

Węgierskie aplikacje będą miały sens, jeśli pracujesz z językiem bez typów zdefiniowanych przez użytkownika, takim jak starszy VBScript lub wczesne wersje VB. Być może także wczesne wersje Perla i PHP. Ponownie, używanie go we współczesnym języku to czysty kult cargo.

W każdym innym języku węgierski jest po prostu brzydki, zbędny i kruchy. Powtarza informacje znane już z systemu typów, a nie należy się powtarzać . Użyj opisowej nazwy zmiennej, która opisuje przeznaczenie tego konkretnego wystąpienia typu. Użyj systemu typów do zakodowania niezmienników i metainformacji o „rodzajach” lub „klasach” zmiennych - np. rodzaje.

Ogólny punkt artykułu Joelsa - niewłaściwy wygląd kodu - to bardzo dobra zasada. Jednak jeszcze lepszą ochroną przed błędami jest - jeśli to możliwe - automatyczne wykrywanie nieprawidłowego kodu przez kompilator.


Języki z typami zdefiniowanymi przez użytkownika nie zawsze sprawiają, że używanie typów zamiast „rodzajów” jest praktyczne. Weź pod uwagę przedrostki „c”, „d”, „ix” z języka węgierskiego Joel's Apps. Czy używasz do tego niestandardowych typów liczb całkowitych we wszystkich współczesnych językach? Nie sądzę. Ponieważ współczesne języki nadal nie mają wbudowanych niestandardowych typów całkowitych dla indeksów, liczebności i różnic między dwiema liczbami. Dopóki nadal będziemy używać standardowych intów, Apps węgierski nie będzie zbędny i użyteczny.
Eldritch Conundrum

27

We wszystkich moich projektach zawsze używam notacji węgierskiej. Uważam, że jest to bardzo pomocne, gdy mam do czynienia z setkami różnych nazw identyfikatorów.

Na przykład, kiedy wywołuję funkcję wymagającą łańcucha, mogę wpisać „s” i nacisnąć spację kontrolną, a moje IDE pokaże mi dokładnie nazwy zmiennych z prefiksem „s”.

Kolejną zaletą jest to, że kiedy przedrostkuję u dla unsigned i i dla znaków int signed, natychmiast widzę, gdzie mieszam podpisane i niepodpisane w potencjalnie niebezpieczny sposób.

Nie pamiętam, ile razy w olbrzymiej bazie kodu zawierającej 75000 linii, błędy były powodowane (przeze mnie i innych) z powodu nazwania zmiennych lokalnych takimi samymi, jak istniejące zmienne składowe tej klasy. Od tego czasu zawsze poprzedzam członków przedrostkiem „m_”

To kwestia gustu i doświadczenia. Nie uderzaj, dopóki tego nie spróbujesz.


1
Kodowanie podpisów w nazwach zmiennych jest świetne, gdy fragment kodu faktycznie zajmuje się podpisywaniem. Używanie tego jako wymówki do egzekwowania konwencji dla wszystkich zmiennych to po prostu domatyzm IMHO.
Plumenator

Masz jednak rację ze zmiennymi składowymi. Ale w językach takich jak Python, gdzie jesteś zmuszony kwalifikować członków za pomocą siebie / tego obiektu, jest to dyskusyjne.
Plumenator

To tylko sztuczka, aby zwiększyć produktywność. Podobnie jak autouzupełnianie IDE. Nie ma w tym nic zasadniczo złego. Uważam, że doświadczonym programistom należy pozwolić na używanie własnego stylu. Zmuszanie kogokolwiek do wyboru określonego stylu jest złe. Pracuję teraz jako samodzielny programista, ale nie narzucałbym stylu nikomu, z kim pracowałem, chyba że przede wszystkim brakowało mu spójnego stylu.
rep_movsd

Więc używasz konwencji nazewnictwa do filtrowania zmiennych, co? Muszę się zgodzić, że to całkiem sprytne . :-) Jednak ze względu na sposób, w jaki jestem podłączony, punkt zakotwiczenia (lub kryterium filtru, jeśli chcesz) jest dla mnie zawsze semantyką. Rzadko typ (chyba, że jest to semantyczny). Mam nadzieje że to miało sens. TL; DR: Nadal będę nazywał zmienne zgodnie z tym , co reprezentują, niż jak są reprezentowane.
Plumenator

1
Głosowałem wtedy za tym, ponieważ byłem za węgierskim. Teraz tego żałuję i nigdy nie wróciłbym do
dodawania prefiksu

22

Zapominasz o najważniejszym powodzie, dla którego warto zawrzeć te informacje. To nie ma nic wspólnego z tobą, programistą. Ma to wszystko wspólnego z osobą, która pojawia się w drodze 2 lub 3 lata po odejściu z firmy i musi to przeczytać.

Tak, IDE szybko zidentyfikuje typy. Jednak podczas czytania długich partii kodu „reguł biznesowych” dobrze jest nie zatrzymywać się na każdej zmiennej, aby dowiedzieć się, jaki to jest typ. Kiedy widzę takie rzeczy, jak strUserID, intProduct lub guiProductID, znacznie ułatwia to czas „rozruchu”.

Zgadzam się, że stwardnienie rozsiane posunęło się o wiele za daleko z niektórymi konwencjami nazewnictwa - kategoryzuję to na stosie „za dużo dobrego”.

Konwencje nazewnictwa są dobre, pod warunkiem, że się ich trzymasz. Przeszedłem przez wystarczająco stary kod, który sprawił, że ciągle wracałem do definicji tak wielu podobnie nazwanych zmiennych, że wciskam „osłonkę wielbłąda” (jak to nazywano w poprzednim zadaniu). W tej chwili wykonuję pracę, która ma wiele tysięcy wierszy całkowicie niekomentowanego klasycznego kodu ASP z VBScript i próba rozwiązania problemu jest koszmarem.


Jako użytkownik VIM (bez IDE, bez podświetlania, bez wskaźnika najechania-powiedz-ci-jaki-typ) w ogóle nie rozumiem tego argumentu. Naturalnie rozumiem, że zmienna o nazwie name jest łańcuchem, a zmienna o nazwie i lub count to int. Czy naprawdę potrzeba sName i iCount? Jak to naprawdę pomaga? Twierdziłbym, że przykład identyfikatora produktu jest szczególnym przypadkiem i może tam byłoby dobrze. Ale nawet wtedy zachowanie spójności i reprezentowanie identyfikatorów produktów z intami lub ciągami znaków wszędzie byłoby znacznie lepszym rozwiązaniem, prawda? Całe nazewnictwo wydaje się wykrętem.
MrFox

6
To dla spójności. Tak, „nazwa” nieodłącznie implikuje ciąg. Ale co według ciebie to „identyfikator użytkownika”? GUID? Strunowy? Liczba całkowita? Nawet coś w rodzaju „acctno” może mieć wartość 42 lub „23X”. Większość kodu zawiera dość skąpą dokumentację. Ten standard pomaga nieco programiście utrzymania ruchu.
David,

1
@David Całkowicie zgadzam się z twoją odpowiedzią - wiedząc na pierwszy rzut oka, jaki jest cel zmiennej, jest to powód, dla którego wolę również prefiks, zwłaszcza w dynamicznym języku, takim jak JS.
Daniel Sokolowski

10

Dodawanie tajemniczych znaków na początku każdej nazwy zmiennej jest niepotrzebne i pokazuje, że sama nazwa zmiennej nie jest wystarczająco opisowa. Większość języków i tak wymaga podania typu zmiennej w deklaracji, więc informacje są już dostępne.

Jest też sytuacja, w której podczas konserwacji trzeba zmienić typ zmiennej. Przykład: jeśli zmienna zadeklarowana jako „uint_16 u16foo” musi stać się 64-bitową bez znaku, stanie się jedna z dwóch rzeczy:

  1. Przejdziesz i zmienisz nazwę każdej zmiennej (uważając, aby nie połączyć żadnych niepowiązanych zmiennych o tej samej nazwie) lub
  2. Po prostu zmień typ i nie zmieniaj nazwy, co tylko spowoduje zamieszanie.

9

Joel Spolsky napisał o tym dobry wpis na blogu. http://www.joelonsoftware.com/articles/Wrong.html Zasadniczo sprowadza się to do tego, aby kod nie był trudniejszy do odczytania, gdy przyzwoite środowisko IDE powie, że chcesz wpisać zmienną, jeśli nie pamiętasz. Ponadto, jeśli wystarczająco podzielisz kod, nie musisz pamiętać, jaka zmienna została zadeklarowana jako trzy strony w górę.


9

Czy zakres nie jest obecnie ważniejszy niż typ, np

* l for local
* a for argument
* m for member
* g for global
* etc

Przy nowoczesnych technikach refaktoryzacji starego kodu wyszukiwanie i zastępowanie symbolu, ponieważ zmieniłeś jego typ, jest żmudne, kompilator wychwyci zmiany typu, ale często nie wyłapie nieprawidłowego użycia zakresu, pomocne są tutaj rozsądne konwencje nazewnictwa.


Z drugiej strony kod prawdopodobnie nie powinien tak bardzo zależeć od zakresu. :-)
Plumenator

8

Nie ma powodu, dla którego nie powinieneś właściwie używać notacji węgierskiej. Jego niepopularność wynika z długotrwałego ostrzeżenia przed niewłaściwym użyciem notacji węgierskiej, szczególnie w interfejsach API systemu Windows.

W dawnych złych czasach, zanim cokolwiek przypominającego IDE istniało dla DOS (jest szansa, że ​​nie miałeś wystarczającej ilości wolnej pamięci, aby uruchomić kompilator pod Windows, więc twój rozwój był wykonywany w DOS), nie otrzymałeś żadnej pomocy od najechanie kursorem myszy na nazwę zmiennej. (Zakładając, że masz mysz). To, z czym musieliście się uporać, to funkcje wywołania zwrotnego zdarzeń, w których wszystko było przekazywane jako 16-bitowe int (WORD) lub 32-bitowe int (LONG WORD). Następnie trzeba było rzutować te parametry na odpowiednie typy dla danego typu zdarzenia. W efekcie większość interfejsu API była praktycznie bez typu.

Rezultatem jest interfejs API o nazwach parametrów takich jak te:

LRESULT CALLBACK WindowProc(HWND hwnd,
                            UINT uMsg,
                            WPARAM wParam,
                            LPARAM lParam);

Zwróć uwagę, że nazwy wParam i lParam, chociaż dość okropne, nie są wcale gorsze niż nazwanie ich param1 i param2.

Co gorsza, Window 3.0 / 3.1 miał dwa rodzaje wskaźników, blisko i daleko. Na przykład wartość zwracana przez funkcję zarządzania pamięcią LocalLock była PVOID, ale wartością zwracaną przez GlobalLock był LPVOID (z „L” przez długi czas). Ta okropna notacja została następnie rozszerzona tak, że l ong p ointer był poprzedzony prefiksem lp , aby odróżnić go od łańcucha, który po prostu został malloc'd.

Nic dziwnego, że wystąpił sprzeciw wobec tego typu rzeczy.


6

Notacja węgierska może być przydatna w językach bez sprawdzania typu w czasie kompilacji, ponieważ pozwala programistom szybko przypomnieć sobie, w jaki sposób używana jest dana zmienna. Nie wpływa to na wydajność ani zachowanie. Ma to poprawić czytelność kodu i jest głównie kwestią gustu i stylu kodowania. Z tego powodu jest krytykowany przez wielu programistów - nie każdy ma takie samo okablowanie w mózgu.

W przypadku języków sprawdzających typ w czasie kompilacji jest to przeważnie bezużyteczne - przewinięcie kilku wierszy w górę powinno ujawnić deklarację, a tym samym typ. Jeśli zmienne globalne lub blok kodu obejmują znacznie więcej niż jeden ekran, masz poważne problemy z projektowaniem i możliwością ponownego wykorzystania. Dlatego jedną z krytyki jest to, że notacja węgierska pozwala programistom mieć zły projekt i łatwo sobie z tym poradzić. To prawdopodobnie jeden z powodów nienawiści.

Z drugiej strony mogą wystąpić przypadki, w których nawet języki sprawdzania typu w czasie kompilacji skorzystałyby na notacji węgierskiej - void pointers lub HANDLE w Win32 API. Te zaciemniają rzeczywisty typ danych i może być korzystne użycie tam notacji węgierskiej. Jeśli jednak można poznać typ danych w czasie kompilacji, dlaczego nie użyć odpowiedniego typu danych.

Ogólnie rzecz biorąc, nie ma trudnych powodów, aby nie używać notacji węgierskiej. Jest to kwestia upodobań, zasad i stylu kodowania.


6

Jako programista Pythona, notacja węgierska rozpada się dość szybko. W Pythonie nie obchodzi mnie, czy coś jest ciągiem - obchodzi mnie, czy może zachowywać się jak ciąg (tj. Czy ma___str___() metodę, która zwraca ciąg).

Na przykład, powiedzmy, że mamy foo jako liczbę całkowitą, 12

foo = 12

Notacja węgierska mówi nam, że powinniśmy wywołać to iFoo lub coś w tym stylu, aby oznaczyć to liczbę całkowitą, abyśmy później wiedzieli, co to jest. Z wyjątkiem Pythona, to nie działa, a raczej nie ma sensu. W Pythonie decyduję, jakiego typu chcę, kiedy go używam. Czy chcę ciąg? cóż, jeśli zrobię coś takiego:

print "The current value of foo is %s" % foo

Zwróć uwagę na %s- ciąg. Foo nie jest łańcuchem, ale %operator wywoła foo.___str___()i użyje wyniku (zakładając, że istnieje). foojest nadal liczbą całkowitą, ale jeśli chcemy, traktujemy ją jako łańcuch. Jeśli chcemy pływaka, traktujemy go jako pływaka. W językach dynamicznie typowanych, takich jak Python, notacja węgierska nie ma sensu, ponieważ nie ma znaczenia, jakiego typu jest coś, dopóki go nie użyjesz, a jeśli potrzebujesz określonego typu, po prostu upewnij się, że rzutujesz go na ten typ (np.float(foo) ), Użyj tego.

Zwróć uwagę, że języki dynamiczne, takie jak PHP, nie mają tej korzyści - PHP próbuje zrobić „właściwą rzecz” w tle w oparciu o niejasny zestaw reguł, których prawie nikt nie zapamiętał, co często prowadzi do nieoczekiwanych katastrof. W takim przypadku przydatny może być jakiś mechanizm nazewnictwa, taki jak $files_countlub $file_name.

Moim zdaniem notacja węgierska jest jak pijawki. Może w przeszłości były przydatne, a przynajmniej wydawały się przydatne, ale obecnie jest to po prostu dużo dodatkowego wpisywania, które nie przynosi wielu korzyści.


Ciekawe, że Twój przykład z .str () w Pythonie nie jest wynikiem tego, że język jest dynamiczny. Java, zdecydowanie nie jest językiem dynamicznym, robi to samo.
Dustman,

C # również robi to samo, każda klasa w języku implementuje, .ToString()aby wszystko można było wydrukować
Electric Coffee

5

IDE powinno przekazywać te przydatne informacje. Węgierski mógł mieć jakiś sens (nie bardzo dużo, ale jakiś rodzaj), kiedy IDE były znacznie mniej zaawansowane.


4
Z drugiej strony nie powinieneś polegać na IDE, które powie ci więcej. W końcu kod można przeglądać poza IDE ...
TraumaPony

5

Aplikacje węgierski są dla mnie greckie - w dobrym tego słowa znaczeniu

Jako inżynier, a nie programista, od razu przeczytałem artykuł Joela o zaletach Apps Hungarian: „Making Wrong Code Look Wrong” . Lubię aplikacje węgierskie, ponieważ naśladuje sposób, w jaki inżynieria, nauka i matematyka przedstawiają równania i formuły za pomocą symboli podrzędnych i nadpisanych (takich jak litery greckie, operatory matematyczne itp.) Weźmy konkretny przykład prawa powszechnej grawitacji Newtona : najpierw w standardowej notacji matematycznej, a następnie w węgierskim pseudokodzie w Apps:

Uniwersalne prawo grawitacji Newtona dla Ziemi i Marsa

frcGravityEarthMars = G * massEarth * massMars / norm(posEarth - posMars)

W notacji matematycznej najbardziej widocznymi symbolami są te reprezentujące rodzaj informacji przechowywanych w zmiennej: siła, masa, wektor położenia itp. Indeksy dolne grają drugie skrzypce, aby wyjaśnić: położenie czego? Dokładnie to robi Apps Węgierski; mówi ci najpierw, jakie rzeczy są przechowywane w zmiennej, a potem zagłębia się w szczegóły - o najbliższym kodzie można dostać się do notacji matematycznej.

Oczywiście silne pisanie może rozwiązać problem bezpiecznego i niebezpiecznego ciągu znaków z eseju Joela, ale nie zdefiniowałbyś oddzielnych typów dla wektorów pozycji i prędkości; obie są podwójnymi tablicami o rozmiarze trzecim i wszystko, co prawdopodobnie zrobisz na jednej, może mieć zastosowanie do drugiej. Co więcej, łączenie pozycji i prędkości (w celu stworzenia wektora stanu) lub wzięcie ich iloczynu skalarnego, ale prawdopodobnie ich nie dodawanie, ma sens. W jaki sposób pisanie pozwoliło na pierwsze dwa, a na drugie uniemożliwiłoby, i jak taki system rozszerzyłby się na każdą możliwą operację, którą chciałbyś chronić? Chyba że chciałeś zakodować całą matematykę i fizykę w swoim systemie pisania.

Co więcej, wiele prac inżynierskich jest wykonywanych w słabo wpisanych językach wysokiego poziomu, takich jak Matlab, lub starych, takich jak Fortran 77 lub Ada.

Więc jeśli masz wymyślny język, a IDE i węgierski aplikacje nie pomagają, to zapomnij o tym - najwyraźniej wielu ludzi to zrobiło. Ale dla mnie, gorzej niż początkujący programista, który pracuje w językach słabo lub dynamicznie wpisywanych, potrafię pisać lepszy kod szybciej z Apps Hungarian niż bez.


4

Jest to niesamowicie zbędne i bezużyteczne w większości nowoczesnych IDE, w których wykonują dobrą robotę, pokazując typ.

Plus - dla mnie - po prostu denerwuje widok intI, strUserName itp. :)


3
Jak powiedział TraumaPony Paulowi Batumowi, nie każdy widzi kod w IDE.
Chris Charabaruk,

4

Jeśli czuję, że przekazywane są przydatne informacje, dlaczego nie miałbym ich umieścić tam, gdzie są dostępne?

Więc kogo obchodzi, co myślą inni? Jeśli uznasz to za przydatne, użyj notacji.


Bo jest tylko jeden ja i miliard innych ludzi, którzy mogliby później zachować mój kod. Ponieważ wszyscy ci ludzie są w zespole (ale jeszcze o tym nie wiedzą), chciałbym mieć jakiś pomysł, czy prześcigną mnie.
Dustman

4

Z mojego doświadczenia wynika, że ​​jest źle, ponieważ:

1 - wtedy przerywasz cały kod, jeśli chcesz zmienić typ zmiennej (tj. Jeśli chcesz rozszerzyć 32-bitową liczbę całkowitą na 64-bitową liczbę całkowitą);

2 - jest to bezużyteczna informacja, ponieważ typ jest już w deklaracji lub używasz dynamicznego języka, w którym rzeczywisty typ nie powinien być tak ważny w pierwszej kolejności.

Co więcej, z językiem akceptującym programowanie ogólne (tj. Funkcje, w których typ niektórych zmiennych nie jest określany, kiedy piszesz funkcję) lub z dynamicznym systemem pisania (tj. Gdy typ nie jest nawet określony w czasie kompilacji), jak nazwałbyś swój zmienne? Większość współczesnych języków obsługuje jeden lub drugi, nawet jeśli jest to ograniczona forma.


4

W książce Joela Spolsky'ego Making Wrong Code Look Wrong wyjaśnia, że ​​to, co wszyscy uważają za notację węgierską (którą nazywa systemowymi węgierskimi), nie jest tym, czym naprawdę miało być (nazywa Apps węgierskim). Przewiń w dół do nagłówka I'm Hungary, aby zobaczyć tę dyskusję.

Zasadniczo Systems Hungarian jest bezwartościowy. Po prostu mówi ci to samo, co powie ci twój kompilator i / lub IDE.

Aplikacje węgierskie mówią, co ma oznaczać zmienna, i mogą być przydatne.


4

Zawsze myślałem, że przedrostek lub dwa we właściwym miejscu nie zaszkodzą. Myślę, że jeśli mogę przekazać coś pożytecznego, na przykład „Hej, to jest interfejs, nie licz na konkretne zachowanie”, tak jak w IEnumerable, powinienem to zrobić. Komentarz może zagracić coś znacznie więcej niż jeden lub dwa symbole znaków.


1
Nigdy nie dostałem ISomethingable. Jeśli jest -able, to i tak oznacza interfejs. (Przynajmniej w java)
tunaranch

4

Jest to przydatna konwencja nazywania formantów w formularzu (btnOK, txtLastName itp.), Jeśli lista kontrolek pojawia się w alfabetycznej liście rozwijanej w twoim IDE.


4

I mają tendencję do używania notacja węgierska z kontrolki ASP.NET tylko , poza tym uważam, że to zbyt trudne do pracy, co kontroluje to co na formularzu.

Weź ten fragment kodu:

<asp:Label ID="lblFirstName" runat="server" Text="First Name" />
<asp:TextBox ID="txtFirstName" runat="server" />
<asp:RequiredFieldValidator ID="rfvFirstName" runat="server" ... />

Gdyby ktoś mógł pokazać lepszy sposób posiadania tego zestawu nazw kontrolnych bez węgierskiego, byłbym skłonny do tego przejść.


4

Artykuł Joela jest świetny, ale wydaje się, że pomija jeden główny punkt:

Język węgierski sprawia, że ​​określony „pomysł” (rodzaj + nazwa identyfikatora) jest unikalny lub prawie niepowtarzalny w całej bazie kodu - nawet w bardzo dużej bazie kodu.

To bardzo ważne w przypadku konserwacji kodu. Oznacza to, że możesz użyć starego dobrego, jednowierszowego wyszukiwania tekstu (grep, findstr, 'znajdź we wszystkich plikach'), aby znaleźć KAŻDĄ wzmiankę o tym 'pomyśle'.

Dlaczego jest to ważne, skoro mamy IDE, które potrafią czytać kod? Ponieważ nie są w tym jeszcze dobrzy. Trudno to zobaczyć w małej bazie kodu, ale oczywiste w dużej - kiedy o „pomyśle” można wspomnieć w komentarzach, plikach XML, skryptach Perla, a także w miejscach poza kontrolą źródła (dokumenty, wiki, bazy danych błędów).

Nawet tutaj trzeba być ostrożnym - np. Wklejanie tokenów w makrach C / C ++ może ukryć wzmianki o identyfikatorze. Z takimi przypadkami można sobie radzić za pomocą konwencji kodowania, a poza tym mają one tendencję do wpływania tylko na mniejszość identyfikatorów w bazie kodu.

PS Do rzeczy, jeśli chodzi o używanie systemu czcionek w porównaniu z węgierskim - najlepiej używać obu. Niewłaściwy kod potrzebujesz tylko wtedy, gdy kompilator go nie złapie. Jest wiele przypadków, w których nie można zmusić kompilatora do przechwycenia go. Ale jeśli jest to wykonalne - tak, zrób to zamiast tego!

Rozważając jednak wykonalność, weź pod uwagę negatywne skutki podziału typów. np. w C # zawijanie „int” typem niewbudowanym ma ogromne konsekwencje. Dlatego ma to sens w niektórych sytuacjach, ale nie we wszystkich.


4

Obalanie zalet notacji węgierskiej

  • Zapewnia sposób rozróżniania zmiennych.

Jeśli typ jest wszystkim, co odróżnia jedną wartość od drugiej, może to dotyczyć tylko konwersji jednego typu na inny. Jeśli masz tę samą wartość, która jest konwertowana między typami, prawdopodobnie powinieneś to zrobić w funkcji przeznaczonej do konwersji. (Widziałem węgierskie pozostałości VB6 używające łańcuchów we wszystkich swoich parametrach metody po prostu dlatego, że nie mogły dowiedzieć się, jak deserializować obiekt JSON lub poprawnie zrozumieć, jak zadeklarować lub użyć typów dopuszczających wartość null. ) Jeśli masz dwie zmienne rozróżniane tylko przez Przedrostek węgierski i nie są one konwersją z jednego do drugiego, musisz z nimi rozwinąć swój zamiar.

  • Dzięki temu kod jest bardziej czytelny.

Odkryłem, że notacja węgierska rozleniwia ludzi swoimi nazwami zmiennych. Mają coś, po czym mogą go odróżnić i nie czują potrzeby, aby rozwodzić się nad jego celem. Oto, co zazwyczaj można znaleźć w węgierskim kodzie notowanym w porównaniu z nowoczesnym: sSQL vs. groupSelectSql ( lub zazwyczaj nie ma sSQL, ponieważ mają używać ORM, który został wprowadzony przez wcześniejszych programistów ), sValue vs. formCollectionValue ( lub zwykle nie ma sValue, ponieważ tak się składa, że ​​znajdują się w MVC i powinny używać jego funkcji wiązania modelu ), sType vs. publicSource itp.

To nie może być czytelność. Widzę więcej sTemp1, sTemp2 ... sTempN z jakichkolwiek resztek węgierskiego VB6 niż wszyscy razem wzięci.

  • Zapobiega błędom.

Byłoby to z racji numeru 2, który jest fałszywy.


3

Słowami mistrza:

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

Jak zwykle ciekawa lektura.

Ekstrakty:

„Ktoś gdzieś przeczytał artykuł Simonyi, w którym użył słowa„ typ ”i pomyślał, że ma na myśli typ, jak klasa, jak w systemie czcionek, jak sprawdzanie typów przez kompilator. Nie. Wyjaśnił bardzo dokładnie dokładnie to, co miał na myśli, mówiąc o „typie”, ale to nie pomogło. Szkoda została wyrządzona ”.

„Jednak wciąż istnieje ogromna wartość dla Apps Hungarian, ponieważ zwiększa kolokację w kodzie, co ułatwia czytanie, pisanie, debugowanie i konserwację kodu oraz, co najważniejsze, sprawia, że ​​niewłaściwy kod wygląda nieprawidłowo”.

Upewnij się, że masz trochę czasu, zanim przeczytasz Joel On Software. :)


Nie ma czasu, gdy mam Stackoverflow. Myślę, że samo skojarzenie Spolsky'ego z projektem musi to robić. :)
Dustman

3

Kilka powodów:

  • Każde nowoczesne IDE poda typ zmiennej, po prostu najeżdżając myszą na zmienną.
  • Większość nazw typów jest zbyt długa (pomyśl HttpClientRequestProvider ), aby można je było rozsądnie używać jako prefiksu.
  • Informacje o typie nie zawierają właściwych informacji, po prostu parafrazują deklarację zmiennej, zamiast określać przeznaczenie zmiennej (pomyśl myInteger vs. pageSize ).

2

Nie sądzę, że wszyscy są temu wściekle przeciwni. W językach bez typów statycznych jest to całkiem przydatne. Zdecydowanie wolę, gdy jest używany do przekazywania informacji, których nie ma w typie. Podobnie jak w C, char * szName mówi, że zmienna będzie odnosić się do łańcucha zakończonego znakiem null - nie jest to niejawne w char * - oczywiście, pomoże również typedef.

Joel napisał świetny artykuł o używaniu języka węgierskiego, aby stwierdzić, czy zmienna jest zakodowana w HTML, czy nie:

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

W każdym razie nie lubię języka węgierskiego, gdy jest używany do przekazywania informacji, które już znam.


Myślę, że pierwsze zdanie może zaprzeczyć odpowiedziom na tej stronie.
Dustman,

@ Dustman Cóż, czy nie wiesz już , że łańcuchy C są zakończone wartością null? Widzę, jak by to było przydatne, gdyby ciąg znaków nie był, ale jest to rzadkie, więc myślę, że użycie konwencji powinno być ograniczone do tych przypadków.
Plumenator

Nie każdy znak * jest łańcuchem c zakończonym znakiem null. Celem języka węgierskiego jest użycie go dla każdej zmiennej, nawet tej, która występuje w typowym przypadku. Ostatecznie czuję się tak, jak ty - i dlatego nie używam tego w C.
Lou Franco


2

Zacząłem kodować mniej więcej w czasie, gdy wynaleziono notację węgierską i kiedy po raz pierwszy byłem zmuszony użyć go w projekcie, którego nienawidziłem.

Po jakimś czasie zdałem sobie sprawę, że jeśli zostało to zrobione prawidłowo, faktycznie pomogło i teraz to uwielbiam.

Ale jak wszystko, co dobre, trzeba się tego nauczyć i zrozumieć, a właściwe zrobienie tego wymaga czasu.


1

Notacja węgierska była nadużywana, szczególnie przez Microsoft, prowadząc do przedrostków dłuższych niż nazwa zmiennej i pokazując, że jest dość sztywna, szczególnie gdy zmieniasz typy (niesławne lparam / wparam, innego typu / rozmiaru w Win16, identyczne w Win32 ).

Tak więc zarówno z powodu tego nadużycia, jak i jego wykorzystania przez M $ został uznany za bezużyteczny.

W mojej pracy kodujemy w Javie, ale założyciel pochodzi ze świata MFC, więc używaj podobnego stylu kodu (wyrównane nawiasy klamrowe, lubię to !, wielkie litery do nazw metod, jestem do tego przyzwyczajony, prefiks jak m_ do członków klasy (pola ), s_ do statycznych elementów członkowskich itp.).

I powiedzieli, że wszystkie zmienne powinny mieć prefiks pokazujący ich typ (np. BufferedReader ma nazwę brData). Co okazało się złym pomysłem, ponieważ typy mogą się zmieniać, ale nazwy nie podążają za nimi lub programiści nie są spójni w używaniu tych prefiksów (widzę nawet aBuffer, theProxy itp.!).

Osobiście wybrałem kilka prefiksów, które uważam za przydatne, z których najważniejszym jest przedrostek b do zmiennych boolowskich, ponieważ są one jedynymi, w których zezwalam na składnię taką, jak if (bVar)(brak użycia autocastowania niektórych wartości na true lub false). Kiedy kodowałem w C, użyłem prefiksu dla zmiennych alokowanych za pomocą malloc, dla przypomnienia, powinno to zostać później zwolnione. Itp.

Więc zasadniczo nie odrzucam tego zapisu jako całości, ale wybrałem to, co wydaje się pasować do moich potrzeb.
I oczywiście, kiedy współtworzę jakiś projekt (praca, open source), po prostu używam istniejących konwencji!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.