LINUX.ORG.RU

[C++][stackoverflow] Как вы отноститесь к использованию префиксов в названии переменных?

 ,


0

2

В этом треде я прочитал сообщение, которое мне показалось настолько простым и изящным, что я решил последовать опыту его автора.

Полная цитата:
====== НАЧАЛО =====
I think (System) Hungarian notation is responsible for most of the «bad rap» that prefixes get.

This notaton is largely pointless in strongly typed languages e.g. «lpsz» to tell you that your string is a long pointer to a nul terminated string, when: segmented architecture is ancient history, C++ strings are pointers to nul-terminated char arrays, and it's not really all that difficult to know that «Name» is a string!

However, I do use prefixes to specify the usage of a variable (essentially «Apps Hungarian», although I prefer to avoid the term Hungarian due to it having a bad and unfair association with System Hungarian), and this is a very handy timesaving and bug-reducing approach.

I use:

  • m for members
  • c for constants/readonlys
  • p for pointer (and pp for pointer to pointer)
  • v for volatile
  • s for static
  • i for indexes and iterators
  • e for events

Where I wish to make the type clear, I use standard suffixes (e.g. List, ComboBox, etc).

This makes the programmer aware of the usage of the variable whenever they see/use it. The most important case is «p» for pointer (because the usage changes from var. to var-> and you have to be much more careful with pointers - checking for NULL etc), but all the others are very handy.

For example, you can use the same variable name in multiple ways in a single function: (here a C++ example, but it applies equally to many languages)

MyClass::MyClass(int numItems)
{
    mNumItems = numItems;
    for (int iItem = 0; iItem < mNumItems; iItem++)
    {
        Item *pItem = new Item();
        itemList[iItem] = pItem;
    }
}

You can see here:

  • No confusion between member and parameter
  • No confusion between index/iterator and items
  • Use of a set of clearly related variables (item list, pointer, and index)

Another great point of «iName» iterators is that I never index an array with the wrong index, and if I copy a loop inside another loop I don't have to refactor one of the loop index variables.

Compare this unrealistically simple example:

for (int i = 0; i < 100; i++)
    for (int j = 0; j < 5; j++)
        list[i].score += other[j].score;
(which is hard to read and often leads to use of «i» where «j» was intended)

with:

for (int iCompany = 0; iCompany < 100; iCompany++)
    for (int iUser = 0; iUser < 5; iUser++)
       companyList[iCompany].score += userList[iUser].score;
(which is much more readable, and removes all confusion over indexing. With auto-complete in modern IDEs, this is also quick and easy to type)

The next benefit is that code snippets do not require any context to be understood. I can copy two lines of code into an email or a document, and anyone reading that snippet can tell the difference between all the members, constants, pointers, indexes, etc. I don't have to add «oh, and be careful because 'data' is a pointer to a pointer», because it's called 'ppData'.

And for the same reason, I can read a line of code, and I don't have to move my eyes out of the line of code in order to understand it. I don't have to search through the code to find if 'data' is a local, parameter, member, or constant. So programmers can read and understand the code significantly faster, because they don't waste time searching up and down.

The 'm' prefix also avoids the (IMHO) hideous and wordy «this->» notation, and the inconsistency that it guarantees (even if you are careful you'll usually end up with a mixture of 'this->data' and 'data' in the same class, because nothing enforces a consistent spelling of the name).

The last major benefit is with Intellisense and auto-completion. Try using Intellisense on a Windows Form to find an event - you have to scroll through hundreds of mysterious base class methods that you will never need to call to find the events. But if every event had an «e» prefix, they would automatically be listed in a group under «e». Thus, prefixing works to group the members, consts, events, etc in the intellisense list, making it much quicker and easier to find the names you want. (Usually, a method might have around 20-50 values (locals, params, members, consts, events) that are accessible in its scope. But after typing the prefix (I want to use an index now, so I type 'i...'), I am presented with only 2-5 auto-complete options. The 'extra typing' people attribute to prefixes and meaningful names drastically reduces the search space and measurably accelerates development speed)

I'm a lazy programmer, and the above convention saves me a lot of work. I can code faster and I make far fewer mistakes because I know how every variable should be used.
==== КОНЕЦ ЦИТАТЫ =====

Какие ещё плюсы и минусы этого подхода? Пока я вижу только плюсы. Хотелось бы конструктивного обсуждения.

Ответ на: комментарий от korvin_

Может, тогда стоит так сделать?

  • ev for events
  • ex for exception

Впрочем, с двумя буквами в префиксе уже теряется лаконичность и изящность, но это не смертельно.

Chaser_Andrey ★★★★★
() автор топика

Вот какой-то мужик говорит «нинужно»:

Мартин Р. Чистый Код

Префиксы m_, которыми когда-то снабжались переменные классов, тоже стали ненужными. Классы и функции должны быть достаточно компактными, чтобы вы могли обходиться без префиксов. Также следует использовать рабочую среду с цветовым выделением членов классов, обеспечивающим их наглядную идентификацию:

public class Part { 
    private String m_dsc; // Текстовое описание 
    void setName(String name) { 
        m_dsc = name;
    }
}
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
public class Part { 
    String description; 
    void setDescription(String description) { 
        this.description = description; 
    } 
} 
Кроме того, люди быстро учатся игнорировать префиксы (и суффиксы), чтобы видеть содержательную часть имени. Чем больше мы читаем код, тем реже замечаем префиксы. В конечном итоге префикс превращается в невидимый балласт, характерный для старого кода.

hor
()

Юзаю только префикс m чтобы вместо this->a = a; было m_a = a; на всякий случай. И то для pimpl классов его не юзаю, больше префиксов в коде не юзаю.

Gorthauer ★★★★★
()
Ответ на: комментарий от Gorthauer

юзаю только a_arg, и то для удобства

[code] class C { int x; void f(int a_x) { x = a_x; } }; [/code]

Ну еще m оправдано. Но уж точно не венгерская

namezys ★★★★
()
Ответ на: комментарий от Harald

Безусловно. Но набирать один раз, а читать - много. Что легче понять - i, j, k или iPeople, iGroup, iPhone? Хотя в простейших случаях это излишне, конечно же.

Надеюсь, нас спасет for loop из C++11.

Chaser_Andrey ★★★★★
() автор топика

Отношусь отрицательно.

urxvt ★★★★★
()
Ответ на: комментарий от Chaser_Andrey
pArray[iGroup][iPeople][iPhone]=bla-bla-blah();

длиннее, может в одну строчку не уместиться и читается труднее, чем

a[i][j][k]=blah();

;)

Harald ★★★★★
()
Ответ на: комментарий от Chaser_Andrey

В простых циклах использую i, j, k, в иных - более внятные имена, для координат например x, y, z удобно, но префиксы как таковые не использую. И вообще стараюсь избегать циклов, foreach/map в большинстве случаев за глаза хватает.

staseg ★★★★★
()
Ответ на: комментарий от Chaser_Andrey

Compare this unrealistically simple example:
// for loop skipped.
(which is hard to read and often leads to use of «i» where «j» was intended)

После этого можно дальше не читать. Лучше почитать синюю книжечку Роба и напарника, где он говорит что чем меньше видимость переменной, тем короче ее имя должно быть.

urxvt ★★★★★
()
Ответ на: комментарий от Harald

Читается легче. Уже по одной этой строке можно немного понять что к чему в программе: что это за трёхмерный массив, какую роль играют его индексы.

unC0Rr ★★★★★
()
Ответ на: комментарий от urxvt

Могу лишь заметить, что на своём (пока довольно скромном, но всё же) опыте и сам допускал ошибки и исправлял других при разработке реальных проектов, когда имела место банальнейшая и досадная опечатка i <-> j, которая не всегда сходу обнаруживалась.

Chaser_Andrey ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Всё в порядке. Просто в повседневных задачах (не связанных с физикой или графикой) встречаются довольно редко.

Chaser_Andrey ★★★★★
() автор топика

Не согласен. Юзаю только постфиксное подчеркивание в мемберах.

panter_dsd ★★★★
()

В одном из проектов видел такой метод именования аргументов: в определении - aSomething, в реализации - theSomething.

schizoid ★★★
()

не забывайте, друзья, что однобуквенные переменные $i, $j, $k, $x работают намного быстрее, чем $iDoorway, $xBuyInsuranceInLondon...

anonymous
()

Какая шизофрения, неужели такой нотацией ещё кто-то пользуется. Кроме виндогогна нигде больше не встречал.

Минус такого подхода очень простой - внимание разработчика должно быть сосредоточено на валидности формализации алгоритма, а не на технических особенностях каких-то там переменных.

Если, например, случайно не в то место засунешь константу то это сразу даст понять компилятор, нахрена этим ещё трахать мозг в названии? Ведь константы именно для этого в языке и есть. Практически тоже самое можно сказать относительно всех префиксов из бреда выше.

mashina ★★★★★
()

Буэ. Приучись писать методы меньше 200та строк и ты её возненавидишь.

Единсвенное из подобного, что я использую это начинаю члены класса знаком подчёркивания. Что-то вроде этого:

class AAA
{
   public:
       AA();
       int something() const;
       void set_something(int);
   private:
       int _something;
};
но писать так начал недавно и то не уверен, что от этого есть толк.

mi_estas
()
Ответ на: комментарий от Chaser_Andrey

> когда имела место банальнейшая и досадная опечатка i <-> j
Ну называй «a» и «b», их уже не спутать.

urxvt ★★★★★
()

Какая-то бессмысленная дискуссия, господа. Это всё равно что обсуждать «брюнетки или блондинки», «чай или кофе». Тут нет места для дискуссии, тут есть место только для докладов о своих личных пристрастиях.

anonymous
()
Ответ на: комментарий от urxvt

> Лучше почитать синюю книжечку Роба и напарника, где он говорит что чем меньше видимость переменной, тем короче ее имя должно быть.

this ^^^

tensai_cirno ★★★★★
()

Хм, единственный префикс который юзаю это `_` для прайват мемберов класса.

Norgat ★★★★★
()

Для членов класса использую суффикс «_». Для итераций i,j,k.

Reset ★★★★★
()
Ответ на: комментарий от Chaser_Andrey
for (int i = 0; i < n; i++) {
   for (int j = 0; j < m; j++) {
      for (int k = 0; k < l; k++) {
         A[i][j] += B[i][k]*C[k][j];
      }
   }
}
for (int iColNumOfA = 0; iColNumOfA < numColsA; iColNumOfA++) {
   for (int iRowNumOfA = 0; iRowNumOfA < numRowsA; iRowNumOfA++) {
      for (int iRowNumOfB = 0; iRowNumOfB < numRowsB; iRowNumOfB++) {
         A[iColNumOfA][iRowNumOfA] += B[iColNumOfA][iRowNumOfB]*C[iRowNumOfB][iRowNumOfA];
      }
   }
}
Reset ★★★★★
()
Ответ на: комментарий от mi_estas

Подчеркивание надо писать в конце, так как имена с подчеркиванием вначале зарезервированы для стандартной библиотеки и есть шанс нарваться на конфликт.

Reset ★★★★★
()
Ответ на: комментарий от Reset

В таких случаях длинные имена переменных не оправданы, согласен.

Chaser_Andrey ★★★★★
() автор топика

Использую префикс k для констант (заимствовано из google coding guidelines) и суффикс в виде подчеркивания для членов класса. Для всего остального есть семантическая подсветка кода, outline и т.п.

m0rph ★★★★★
()
Ответ на: комментарий от Reset

> Подчеркивание надо писать в конце, так как имена с подчеркиванием вначале зарезервированы для стандартной библиотеки и есть шанс нарваться на конфликт.

В свое время специально изучал эту тему и если я правильно помню в стандарте не говорится, что перфикс из подчеркиваний для членов классов зарезервирован. Но на всякий случай использую как рекомендуют.

m0rph ★★★★★
()

Использую понятные (иногда длинные) имена для полей класса, при совпадении имени аргумента и поля к полю обращаюсь через this. В яве так же.

note173 ★★★★★
()
Ответ на: комментарий от Gorthauer

Аналогично, а префикс m нужен для того чтобы getter в Qt стиле (без get) писать.

kamre ★★★
()
Ответ на: комментарий от namezys

> Если вам вдруг понадобилась венгерская нотация, значит у вас проблемы с кодом.

Есть два типа венгерской ноттации - системная и для приложений. Системная - это говно, которое почему то прижилось среди вендопрограммеров.

andreyu ★★★★★
()
Ответ на: комментарий от trashymichael

> зачем дублировать типы переменных в префиксах, постфиксах, етц?

Это дурацкая системная венгерская. В правильной венгерской для приложений описывается назначение переменной, а не ее тип.

andreyu ★★★★★
()

> (Usually, a method might have around 20-50 values (locals, params, members, consts, events)
Вон из профессии!

По теме - лицам пишущим классы-методы-простыни с 50-ю значениями в namespace никакие префиксы и суфиксы не помогут.

grassmeister
()

плохо отношусь, это лишняя информация

shty ★★★★★
()
Ответ на: комментарий от Reset

Подчеркивание надо писать в конце, так как имена с подчеркиванием вначале зарезервированы для стандартной библиотеки и есть шанс нарваться на конфликт.

в своём namespace ЕМНИП можно, если не делать бездумно using namespace tralala...

shty ★★★★★
()
Ответ на: комментарий от grassmeister

>лицам пишущим классы-методы-простыни с 50-ю значениями в namespace никакие префиксы и суфиксы не помогут.

Ужос, разработчикам Qt надо срочно раскаяться перед вами за допущенный непрофессионализм.

QWidget Class Reference — это даже не простыня.

http://doc.qt.nokia.com/4.7-snapshot/qwidget.html

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.