Чи є угорська нотація все ще корисною практикою? [зачинено]


23

Я шукав форум, але не зміг знайти відповіді, чому цього слід уникати, лише чому це не срібна куля. Тож я не думаю, що це питання є дублікатом.

Чи є ВАЛІДНА причина, чому я повинен вивчити Системи Угорська, до яких я звик?

Поки я бачу такі переваги в його використанні:

  • Послідовна назва змінної
  • Ви бачите тип без пошуку (intellisense мертвий / індексує половину часу, тому це все-таки поважна причина)
  • Семантика все ще може бути упакована у другу частину назви

І наступні недоліки:

  • Це дратує деяких людей (не знаю, чому)
  • Якщо тип змінено, тип може не відповідати іменуванню змінної (я не думаю, що це дійсна причина, типи змінюються рідко, і у вас є "перейменувати все")

Так чому:

vector<string> vecCityNames;
wstring strCity = L"abc";
//more code here
vecCityNames.push_back(strCity);

гірше, ніж:

vector<string> cityNames;
wstring city = L"abc";
//more code here
cityNames.push_back(city);//Are we pushing back int on a queue? Float on a stack? Something else?

4
якщо intellisense мертвий, ваш код недійсний. Якщо він недійсний, навіщо вважати, що ім'я змінної є правильним?
Bubblewrap

6
@Bubblewrap: Більшість інтелігентних реалізацій баг на 3 секунди періодично, навіть на дійсному коді. І іноді вони взагалі не працюють, навіть незважаючи на компіляцію коду та посилання. Ми говоримо про досить розумні проекти.
Coder

9
не повинно vectCityNamesбути vectStringCityNamesстільки для вашої послідовної аргументації, і це "питання" є скоріше сказом, ніж чим-небудь, ви думаєте, це слід закрити.

8
Що ви вважаєте "поважною" причиною?
Адам Лір

15
Я не думаю, що ваш другий приклад заплутаний у тому, як ваш коментар вказує, що він є. Сенс cityNames.push_back(city)досить зрозумілий. Це список назв міст, і ви додаєте його.
Кріс Берт-Браун

Відповіді:


62

Раніше я його використовував (багато років тому), і більше цього не роблю. Основна причина полягає в тому, що це зайве в мовах ООС із сильним набором тексту (C ++, Java), якими я, здається, користувався більшу частину своєї кар’єри. У цих мовах, якщо я добре визначу свої типи, компілятор може і застосовуватиме безпеку для мене типу. Отже, будь-які префікси іменування - це просто безлад, який робить імена довшими, тим важче читати та шукати.

У будь-якій добре написаній програмі OO більшість ваших змінних - це (посилання на) визначені користувачем типи. Якщо ви будете префіксувати їх одним і тим же загальним тегом (наприклад, oдля "об'єкта"), ви не отримаєте від цього ніякої користі, лише недоліки. Якщо ви прифіксуєте їх за допомогою тегів, характерних для типу, ви потрапляєте в лабіринт, намагаючись знайти різні абревіатури для тисячі різних типів із часто подібними іменами *, і пам'ятати, щоб змінити їх усі, коли тип або його назва змінюється (що є зовсім не рідкість у доглянутій програмі).

Звичайно, це не стосується мов, що не входять в ООС, і може не стосуватися слабко та / або динамічно набраних мов (я не маю досвіду роботи з цими, окрім С). Ні для суббоптимальних редакторів / IDE без використання IntelliSense (або його місцевого еквівалента). І це лише мої 2 копійки. Тож якщо угорська нотація працює для вашої команди та вашого проекту, займіться цим. Важливо - домовитись про це (як і про узгоджений стиль кодування взагалі) до початку проекту, і дотримуватись його постійного у будь-який час.

* Тільки короткий список з нашого поточного проекту: у нас є Charge, ChargeBreakdown, ChargeCalculator, ChargeDAO, ChargeDTO, ChargeLineHelper, ChargeMaps, ChargePairі ChargeType, серед інших. Більше того, у нас також є Contracts, Countries, Checkouts, Checkins ... і це лише буква C, в проекті, який, ймовірно, ОП не може назвати "розумним розміром".


Відмова: Я насправді угорський, тому я вважаю, що можу говорити з цього приводу з владою ;-)


"Сильне введення тексту" - Якщо C ++ мав справді сильну систему типів, вам не доведеться вставляти типи в ім'я змінної як хак.
Майкл Бердж

19
@MichaelBurge: У цьому справа. Вам не доведеться. Тому що це робить.
DeadMG

8
+1 для точки про визначені користувачем типи. Використання змінних, названих iPosабо fAmountможе бути допустимим, але спробуйте працювати над кодовою базою, де кожній об'єктній змінній надається надмірний шестицифровий префікс, який повідомляє лише про те, що це "покажчик на структуру".

2
Я б зробив виняток для графічних інтерфейсів, де вам потрібно зберігати ручку для кожного елемента управління, окрім його значення, тому текст та hText, а не повинні думати іншу назву для поля введення. Особливо важливо в системах, де ручка - це лише int, а не особливий тип.
Мартін Бекетт

1
Я вважаю, що основним місцем, де Ява повинен був рекомендувати використання угорської нотації, є розмежування посилань на випадки, які можуть бути мутовані, але ніколи не надані (наприклад, char[]утримуваних а StringBuilder), та посилань на випадки, які можуть бути не змінені, але Ви можете поділитися з речами, які не мутирують їх (наприклад, char[]утримується користувачем String, яким можна ділитися між кількома Stringпримірниками). Обидва поля одного типу char[], але вони містять речі, які дуже відрізняються. Дуже багато помилок, пов’язаних з
мутаційністю,

35

Чому std::vector<string> vecCityNames;погано?

Проблема з угорським позначенням, оскільки його зазвичай використовують, що якщо профілювання показує, що назви міст краще зберігати в а std::deque, всі назви змінних, що посилаються на об'єкт такого типу, раптом матимуть оманливу назву.

Ви збираєтесь перейменовувати всі змінні? Ви коли-небудь намагалися зробити це у великому проекті? За допомогою Мерфі (а хлопець там неймовірно корисний) хтось десь неодмінно використає змінні, які називаються чимось на зразок deqCityNames, змушуючи зміни змінити складку, залишаючи вас годинами сидіти з кодом, який протягом півроку ніхто не наважувався навіть подивитися у страху, щоб не покусати отруйного звіра.

Однак, наскільки я знаю, як у Чарльза Симоні придумав угорський, префікс позначав змінні вживання змінних , а не синтаксичний тип . Тобто, відповідний префікс для вашого списку назв міст, незалежно від того, для якого типу він реалізований, мабуть, був би listCityNames(або lstCityNames, якщо listдля вас недостатньо загадковим).

Але я вважаю цей префікс досить зайвим, тому що множина ("імена") вже передає, що це купа міст. Підсумок: Коли ви обережно вибираєте свої ідентифікатори, угорська нотація рідко потрібна. OTOH, спосіб його звичайного використання, з часом, фактично завдає шкоди коду.


6
@Coder: тип використовується протягом усього проекту, і всі змінні цього типу матимуть префікс. Вам доведеться перейменовувати не одну глобальну змінну, а сотні локальних.
sbi

7
Ви повинні додати посилання на публікацію в блозі Джоела Спольського, де він пропонує своє пояснення, чому використання змінного типу для створення угорського сповіщення є нерозумінням того, про що йдеться. Ваше добре, але деякі люди можуть шукати щось більш авторитетне, і ви можете використовувати це для створення резервної справи. joelonsoftware.com/articles/Wrong.html
Shane Wealti

2
@Coder: На жаль, typedefце серйозно занижений інструмент
sbi

4
@Shane: Я записав власну думку з цього приводу. Якщо це трапляється з Джоелем, то це добре зі мною, тому що я ціную його думку, навіть якщо я не згоден з деякими з них. Але я не бачу потреби звертатися до інших "владних структур", щоб підкріпити власну думку, коли це базується на більш ніж десятирічному важкому досвіді. Приємно, що ви опублікували це посилання, хоча завжди добре бачити думки інших людей для порівняння.
sbi

4
Давним-давно я був хлопцем CVS для магазину, і один з найкращих розробників змінив ініціали (операція по зміні статі тощо), і його та її імена не мали однакових ініціалів). Щоразу, коли вона торкалася файлу (або подібного), вона змінювала всі його ініціали на нову форму. Я вважав це надзвичайно дратівливим, оскільки в нас відбулися всілякі незначні зміни в історичних особливостях, і важко було зрозуміти, що насправді було змінено і чому. Змініть vecCityNamesна deqCityNamesкілька сотень файлів, і ви зробите те саме.
Девід Торнлі

15

З будь-якої причини, існуючі відповіді тут, здається, танцюють навколо обґрунтування угорської нотації, не заявляючи це прямо. Угорська нотація корисна для додавання інформації про тип (в теоретичному сенсі типу ), коли це було б важко зробити в самій мові . Як це буває, користуватися системою типу C ++ або Java таким чином не так складно, щоб угорська нотація (як це зазвичай описано) абсолютно зайва, і це, мабуть, призвело до зворотного зв'язку проти неї - це додає роботи програміста підтримувати ці анотації у всіх наших змінних джерелах, але надає майже ніякого додаткового значення (і навіть може завдати шкоди, оскільки код виглядає більш захаращеним).

З іншого боку, якщо ви обмежуєте використання угорської нотації для введення інформації (знову ж таки, в теоретичному сенсі типу ), яка не єприродно інкапсульована мовою, то це може бути дуже корисно. Наприклад, C і C ++ передають посилання масиву як типи вказівників, але посилання масивів і покажчики мають різні операції, які слід виконувати проти них: масиви можна індексувати за межами першого елемента, тоді як покажчики не повинні. Це корисна інформація, яка втрачається в системі типу, як тільки масив передається функції в якості аргументу. Таким чином, у нашій групі ми прийняли анотації змінних імен у коді C та C ++, щоб розрізнити, чи змінна вказівника насправді є вказівником на один елемент, або вказівник на масив. Прийняття цієї конвенції частково спричиняє значне скорочення виникнення проблем з корупцією пам’яті в нашій кодовій базі.


Угорщина зазнала невдачі в тому, що вона неправильно використовувалась командою WinAPI для кодування синтаксичного типу змінної , а не її семантичного значення . (Подумайте dwпроти cb.) Це не те, що його початкова форма була б менш корисною для мов ОО: Індекс все ще є індексом, навіть якщо він зберігається у типі класу, а не вбудованому.
sbi

1
+1 для вказівки, що справжній аргумент стосується теорії типів. Угорська нотація - це техніка розширення системи типів додатковою інформацією, і як такої слід порівнювати та протиставляти іншим прийомам розширення системи типу (наприклад, шаблонам, typedef тощо), а не обговорювати її естетичні переваги (або його відсутність).
Даніель Приден

1
Питання стосується конкретно "Системи Угорщини", безглуздого дублювання заявленого типу, без зайвої семантичної інформації. Можливо, може бути використане оригінальне поняття "Угорська нотація" семантичних тегів для надання інформації, що перевищує дозволений синтаксисом мови (у деяких мовах, включаючи C, хоча не на C ++, де ви можете зробити це надійніше за визначеними користувачем типами ), але це не в чому питання.
Майк Сеймур

10

Це дратує деяких людей (не знаю, чому)

Причина, яка мене дратує, полягає в тому, що це невеликий набір швидкості на кожен окремий ідентифікатор, який уповільнює моє візуальне сканування коду. sIt's mAs bff pYou kHad zTo qRead iEnglish cText lLike uThis.


9

Ненависть - це занадто сильне слово, ІМО. Ви можете написати свій код будь-яким способом; Я просто вважаю за краще не використовувати угорські позначення у власному коді, і даючи вибір, я також вважаю за краще не читати його та не працювати з ним у коді інших людей.

Ви запитали, чому деякі люди вважають угорську нотацію дратівливою. Я не можу говорити за інших, але причини, які мене дратують:

  1. Це некрасиво. Угорська має цілком розумні імена і робить вигляд, що означає код. Після того, як ви інтерналізували цей код, я впевнений, що це має сенс, але для непосвячених це виглядає так, як хтось розв’язав манглер імені C ++ у моєму вихідному коді.

  2. Це зайве. Декларація змінної визначає її тип; Я не відчуваю необхідності повторювати цю інформацію в назві змінної. Це не вірно в кожній мові: наприклад, у Perl такі сигіли, як @ або $, що мають попереднє ім'я змінної, по суті визначають тип змінної, тому у вас немає іншого вибору, крім того, як використовувати їх.

  3. Це вирішує проблему, якої у мене немає. Методи та функції не повинні бути настільки довгими, що вам доведеться важко знайти декларацію локальної змінної чи параметра, і вони не повинні включати стільки змінних, щоб у вас виникли проблеми відслідковувати, що до чого. Оголошення локальних змінних, близьких до коду, який їх використовує, також допомагає в цьому відношенні. Компілятори C минулого вимагали, щоб усі локальні змінні були оголошені на початку функції, але це обмеження було давно знято.

  4. Це неповно. Угорська нотація була винайдена для мови (BCPL), яка не мала типової системи, і пізніше була широко використана мовою (С), яка мала досить обмежену кількість рідних типів. IMO, він не працює добре з такими мовами, як C ++ або Java, які мають розширені системи. Чому я хотів би використовувати префікс для позначення типу змінної, яка є нативним типом, наприклад char [], але не тієї, що є класом? Крім того, якщо я почну винаходити префікси, як vecдля класів, я закінчуся великою ієрархією префіксів, паралельних моїй ієрархії класів. Якщо це звертається до вас, ви раді до цього; просто думка про це доставляє мені головний біль.

  5. Це неоднозначно , принаймні, як я це розумію. Яка різниця між szFooі pszFoo? Перший - це нульовий завершений рядок, а другий - вказівник на нульовий завершений рядок. Але в C або C ++, наскільки я знаю, будь-яка струнна змінна є ефективно вказівником, так вони однакові чи ні? Який я повинен використовувати? Фактична відповідь насправді не має значення - справа в тому, що я не можу розпізнати відповідь саме тим позначенням, яке повинно допомогти мені уникнути подібних питань. Декларація змінної, з іншого боку, повинна бути однозначною, оскільки саме її використовує компілятор.

Це ті речі, які мене дратують щодо угорської нотації. Хоча, навіть як група, я не думаю, що вони повністю пояснюють, чому угорська значною мірою відмовилася. Ось три найбільші причини, що більшість програмістів не використовують угорську:

  1. Немає вагомих причин використовувати його. Див. Пункти 3 та 4 вище. Я, мабуть, міг би жити з досадами, якби угорська запропонувала якусь велику перевагу перед тим, як не використовувати угорську, але я її не бачу, і, мабуть, більшість інших людей теж не мають. Мабуть, найкраще в угорській мові було те, що це широко використовувана конвенція, і якщо ви дотримуєтесь стандартного використання, ви можете з розумом очікувати, що інші програмісти з подібними навичками зможуть зрозуміти позначення.

  2. Зростає вплив компаній, які не є Microsoft. Напевно, справедливо сказати, що більшість програмістів, які прийняли угорську нотацію, зробили це, тому що саме так написав Microsoft код, і його часто простіше йти з потоком. Такі компанії, як Google та Apple, мають набагато, значно більші сфери впливу, ніж раніше, і більше програмістів, ніж будь-коли раніше, переймають стилі тих компаній та інших, які здебільшого ухиляються від угорської. (Справедливо лише зазначити, що ви все ще бачите деякі залишки, наприклад, Google і Apple часто використовують префікс 'k' для постійних імен.)

  3. Microsoft сама відмовилася від угорської. Якщо ви переглянете розділ Загальних конвенцій Майкрософт у своїх інструкціях щодо кодування, ви побачите, що він написаний жирним шрифтом: Не використовуйте угорські позначення.

Відповідно, однією вагомою причиною припинення використання угорських позначень є:

Популярність угорських нотацій зменшилася до того, що конвенція більше не корисна. На сьогоднішній день набагато менше програмістів використовують або навіть розуміють угорську мову, і тому конвенція є набагато менш ефективною для передачі інформації, яку вона повинна. Якщо вам здається корисним способом написання коду у власних особистих проектах, то мало підстав зупинятися. Однак якщо ви пишете код як частину команди, яка не використовує угорську мову, це може стати стіною між вами та рештою команди замість успішної комунікаційної стратегії.


"Яка різниця між szFooта pszFoo"? Один char*, інший char**, мені знадобився 0,25 сек, щоб сказати різницю. Спробуйте перемогти це з Intellisense.
Кодер

2
@Coder, pnFooмабуть, буде int*, ні int**, тому ви повинні знати, що szтакож означає вказівник. Я впевнений, що це не велика проблема для обмеженої кількості типів, які встановили угорські префікси, але в будь-якому великому проекті кількість типів визначається тисячами. Я не знаю про Intellisense, але IDE постійно покращувався протягом останніх 25 років, і я очікую, що ця тенденція збережеться.
Калеб

8

Поки я бачу такі переваги в його використанні:

  • Послідовна назва змінної

Якщо я називаю всі свої змінні за персонажами з "Сімпсонів", це теж відповідає, але чи користь це?

  • Ви бачите тип без пошуку (intellisense мертвий / індексує половину часу, тому це все-таки поважна причина)

Це єдина поважна причина, заснована на слабкості одного конкретного інструменту ...

  • Семантика все ще може бути упакована у другу частину назви

Це не користь; ви просто заявляєте про відсутність ( масового ) мінусу.


6

IDE тривіально підкаже мені, що таке тип змінної, коли я клацну на неї мишкою. То навіщо турбуватися дублювати цю інформацію? По суті, Система Угорського Позначення - це порушення DRY, з усіма підводними каменами, які пов'язані з цим. Коли ця інформація є тривіально доступною в сучасних умовах, немає жодної причини платити цю ціну.

Послідовність не є перевагою сама по собі. Не називати їх типом також послідовно. Ви мали б невідповідність, якби лише деякі змінні мали свої типи в імені. А упаковка семантики у другу частину просто "Ну, це не так вже й погано". Всі інші отримують використовувати цілу назву для семантики. У вас немає реальних переваг.


4
"IDE банально скаже мені, що таке тип змінної, коли я клацну на неї курсором миші". У великих проектах я вважаю цю особливість надзвичайно ненадійною / повільною. ctrl + пробіл, ctrl + пробіл, ctrl + пробіл, ctrl + пробіл, ctrl + пробіл, не йти ...
Coder

3
Отримайте нову IDE. Або SSD, який творить чудеса. Або просто включити менш зайві заголовки.
DeadMG

1
Навіть якщо IDE занадто повільний, коли показує тип змінної або якщо він просто не здатний до цього, методи / функції повинні бути короткими, так що декларація змінної ніколи не буде дуже далеко від її використання.
Кевін Панько

6

Ще один момент з традиційними формами угорського позначення - це, як правило, префікси. Тут є дві проблеми:

1) Людському читачеві, як правило, спочатку подобається найважливіша інформація, у більшості форм угорської мови кодована інформація, мабуть, має менш важливе значення, ніж сама назва.

2) Префікси впливають на лексичне сортування, тому, якщо, наприклад, ви будете використовувати префікс для позначення інтерфейсів або класів, а ваш IDE забезпечує відсортований список цих, пов'язані класи / інтерфейси будуть відокремлені в цьому списку.


2

Зрозуміло, що це зводиться до думок, тому працювати з фактами тут буде складно. Особисто я вважаю, що аргумент для угорської нотації трохи тонкий у сильно набраних, об'єктно-орієнтованих мовах. На мій досвід, програми OO, як правило, вирішують складність, зберігаючи класи узгодженими та стислими, і те саме можна сказати про функції. Це означає, що при всіх інших рівнях ви закінчуєте:

  • Більше класів / типів
  • Коротші методи

Тепер, якщо ви хочете використовувати угорські позначення, ви повинні вирішити, чи застосовувати його через дошку, або просто використовувати його для певних пільгових типів та класів (наприклад, основних класів бібліотеки). Останнє для мене не має сенсу, і перше призводить до "лабіринту спроб знайти різні абревіатури до тисячі різних типів", про які мав на увазі Петер Тьорек. Це означає, що у підтриманні списків абревіатур є значна накладні витрати, і зазвичай "послідовне іменування змінної" виходить з вікна.

Другий пункт про більш короткі методи означає, що в більшості випадків вам не доведеться проходити сотні рядків коду, щоб перевірити, що таке змінна. Назви змінних трохи ретельніше буде усунути деякі ваші інші питання - наприклад, cityNameпроти просто city. Я би сподівався, що cityNameце не поплавок :)

Щодо того, що це дратує людей - знову ж таки, це, мабуть, аж до того, щоб звикати до цього чи ні. Але як хтось до цього не звик, я можу вам сказати, що використання угорської нотації порушує потік коду для моїх очей, утрудняючи швидке читання. Підводячи підсумок, я не кажу, що це не має жодних заслуг (хоча я не обговорював деякі його недоліки, що стосуються рефакторингу тощо), я кажу, що докладати зусиль не варто для сильно набраних мов OO.


1

Я не знаю в контексті C ++, але в світі Java / C # я б більше хотів мати значущі імена, які передають або доменну мову, або контекст, ніж говорити мені, що strFirstNameце String; повинно бути очевидним, що це рядок, або ім'я потрібно переробити, щоб передати кращі наміри. Якщо вам потрібен префікс, щоб знати тип того, з чим ви працюєте, я можу стверджувати, що ваше називання є непослідовним, недостатньо описовим або прямо неправильним. У сучасних мовах я завжди віддаю перевагу більш довгим іменам, які не залишають двозначності, ніж розпливчасті або неоднозначні назви.

Єдиний раз , коли я використовую угорський для елементів управління ASP.NET, і це більше, IA) не повинні вводити що - то дуже довго , як CustomerFirstNameTextBoxпроти txtCustomerFirstName, і Б) Так Intellisense сортує всі типи управління. Я відчуваю себе "брудною", навіть роблячи це, хоча мені просто ще потрібно знайти кращий шлях.


0

Мех - це справді все, що стосується особистих уподобань, якими б важкими не були спроби раціоналізувати свій вибір. Я особисто дотримуюся правила "Коли в Римі ..." і використовую угорський у коді, який дуже закликає API API. Щодо коду незалежно від платформи, я схильний дотримуватися стилю стандартної бібліотеки C ++.


0

Відповідь полягає в цьому питанні: Скажіть, будь ласка, як називати такі змінні:

char * nullTerminatedString;
wchar * nullTerminatedWideString;
string stlString;
wstring stlWideString;
CString mfcString;
BSTR comString;
_bstr_t atlString;

Додайте до цих постійних рядків, вказівник на ці та постійні вказівники на них.


3
szFoo, wczFoo, strFoo, (w)strFoo, strFoo, bstrFoo,bstrFoo
Coder

0

Я категорично не люблю форму описуваної угорською нотацією. Причина? Він не займає 90% часу.

Наприклад, трохи (еквівалентний C ++. Насправді написаний у Delphi) код із застарілого проекту, який я змушений терпіти:

pRecords[0]->FooMember=10;

... pRecord є змінною, вона має тип TRecordList. TRecordList *pRecords[10];

Це клас, що складається з оріоерті з ім'ям FooMember, який вказує на fFooMember ... або mFooMember залежно від того, "поле" чи "член" (підказка: вони те саме)

Проблеми? fFooMemberможе бути чимось на зразок FooMember_, оскільки ми завжди будемо отримувати доступ до нього через публічну власність FooMember. pЗаписи? Це досить очевидно, що це вказівник на те, що ви його зневажаєте всюди. TRecordList? Коли ви, можливо, можете переплутати ім'я типу та об'єкт цього типу? Компілятор буде кричати на вас, а типи майже не використовуються там, де об’єкти є (крім статичних властивостей / методів)

Тепер є одне місце, де я використовую угорські позначення. Це під час роботи з великою кількістю змінних інтерфейсу, які мали б те саме ім'я, що й інші змінні інтерфейсу або звичайні змінні.

Наприклад, якщо б у мене була форма для вашого Імені.

У мене був би клас на ім'я FirstNameForm. У ньому lblFirstName та txtFirstName для мітки та текстового поля відповідно. І загальнодоступне властивість FirstName для отримання та встановлення імені в текстовому полі.

Це також можна вирішити, використовуючи FirstNameLabel і FirstNameTextBox, але я вважаю, що це стає довго, щоб набрати. Особливо з чимось на зразок GenderDropDownList та подібним.

Таким чином, угорська нотація, в кращому випадку, дратує на систематичному рівні і в гіршому випадку шкідлива (оскільки інші відповіді дають проблеми з рефакторингом і послідовністю).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.