C# code style: подчеркивания в именах переменных
Тем временем я нашёл аргумент в пользу подчёркиваний. Оказывается, некоторые разработчики передают в методы переменные, названные как локальные поля. При этом они не пользуются ReSharper-ом или другими средствами, спасающими от глупостей.таких ситуации крайне редки. Странно, что небольшое количество ситуаций оказывает влияние на именование часто используемых приватных полей.
А вообще, у макрософта написано
Do not use underscores, hyphens, or any other nonalphanumeric characters.
Do not use Hungarian notation.
Hungarian notation is the practice of including a prefix in identifiers to encode some metadata about the parameter, such as the data type of the identifier.
http://msdn.microsoft.com/en-us/library/ms229045.aspx
А вообще, у макрософта написаноДа, я в курсе. В Code Analysis для .NET есть Naming Rules. Кстати, вполне жестокие.
Да, я в курсе. В Code Analysis для .NET есть Naming Rules. Кстати, вполне жестокие.тогда зачем вынес на обсуждение?
Первое - это попытка добавить какой-то смысл в имя переменной.
С этим все ясно — подчеркивание нормальные прогеры не используют, те кто используют не хватило ума подумать на тему красивого согласованного naming convention, и посмотреть рекомендации. Т.е. да я по одному подчеркиванию могу сделать вывод об уровне программиста .
тогда зачем вынес на обсуждение?Потому что забыл про них. Они настолько жестокие, что их я обычно отключаю. Вместе, например, с подписыванием сборок.
С этим все ясно — подчеркивание нормальные прогеры не используют, те кто используют не хватило ума подумать на тему красивого согласованного naming convention, и посмотреть рекомендацииPEP8:
Prescriptive: Naming Conventions
Names to Avoid
Never use the characters `l' (lowercase letter el `O' (uppercase
letter oh or `I' (uppercase letter eye) as single character variable
names.
In some fonts, these characters are indistinguishable from the numerals
one and zero. When tempted to use `l', use `L' instead.
Package and Module Names
Modules should have short, all-lowercase names. Underscores can be used
in the module name if it improves readability. Python packages should
also have short, all-lowercase names, although the use of underscores is
discouraged.
Since module names are mapped to file names, and some file systems are
case insensitive and truncate long names, it is important that module
names be chosen to be fairly short -- this won't be a problem on Unix,
but it may be a problem when the code is transported to older Mac or
Windows versions, or DOS.
When an extension module written in C or C++ has an accompanying Python
module that provides a higher level (e.g. more object oriented)
interface, the C/C++ module has a leading underscore (e.g. _socket).
Class Names
Almost without exception, class names use the CapWords convention.
Classes for internal use have a leading underscore in addition.
Exception Names
Because exceptions should be classes, the class naming convention
applies here. However, you should use the suffix "Error" on your
exception names (if the exception actually is an error).
Global Variable Names
(Let's hope that these variables are meant for use inside one module
only.) The conventions are about the same as those for functions.
Modules that are designed for use via "from M import *" should use the
__all__ mechanism to prevent exporting globals, or use the older
convention of prefixing such globals with an underscore (which you might
want to do to indicate these globals are "module non-public").
Function Names
Function names should be lowercase, with words separated by underscores
as necessary to improve readability.
mixedCase is allowed only in contexts where that's already the
prevailing style (e.g. threading.py to retain backwards compatibility.
Function and method arguments
Always use 'self' for the first argument to instance methods.
Always use 'cls' for the first argument to class methods.
If a function argument's name clashes with a reserved keyword, it is
generally better to append a single trailing underscore rather than use
an abbreviation or spelling corruption. Thus "print_" is better than
"prnt". (Perhaps better is to avoid such clashes by using a synonym.)
Method Names and Instance Variables
Use the function naming rules: lowercase with words separated by
underscores as necessary to improve readability.
Use one leading underscore only for non-public methods and instance
variables.
To avoid name clashes with subclasses, use two leading underscores to
invoke Python's name mangling rules.
Python mangles these names with the class name: if class Foo has an
attribute named __a, it cannot be accessed by Foo.__a. (An insistent
user could still gain access by calling Foo._Foo__a.) Generally, double
leading underscores should be used only to avoid name conflicts with
attributes in classes designed to be subclassed.
Note: there is some controversy about the use of __names (see below).
Constants
Constants are usually declared on a module level and written in all
capital letters with underscores separating words. Examples include
MAX_OVERFLOW and TOTAL.
я имел ввиду C#
А как вы оформляете инициализацию по требованию?
Я, например, часто использую такой код:
string _state = null;
public string State
{
if(_state==null)
{
_state=LoadState;
}
return _state;
}
Подчеркиванием в данном случае я показываю, что остальным программистам, и мне в том числе, стоит избегать использования поля _state в других методах, а нужно пользоваться свойством State.
Подчеркиванием в данном случае я показываю, что остальным программистам, и мне в том числе, стоит избегать использования поля _state в других методах, а нужно пользоваться свойством State.я ж постил в этом треде цитату относительно подобных рассуждений, все это хрень.
я ж постил в этом треде цитату относительно подобных рассуждений, все это хрень.там нет ответа почему для той ситуации, которую привел (создание по первому требованию) - не стоит использовать подчеркивание.
как ты предлагаешь называть переменные из примера ?
там нет ответаВо-первых, там явно указано
Do not use underscores, hyphens, or any other nonalphanumeric characters.
Во-вторых, вот это
Подчеркиванием в данном случае я показываю, что остальным программистам, и мне в том числе, стоит избегать использования поля _state в других методах, а нужно пользоваться свойством State.
информация не о тех данных, которые хранятся в переменной _state, а информация о самой переменной _state, т.е. это можно отнести к метаданным. И тут подходит вторая цитата
Do not use Hungarian notation.
Hungarian notation is the practice of including a prefix in identifiers to encode some metadata about the parameter, such as the data type of the identifier.
как ты предлагаешь называть переменные из примера ?
не вижу причин, по которым для инициализации по требованию менять naming convention.
private string state;
public string State
{
if(state == null)
{
state = LoadState;
}
return state;
}
не вижу причин, по которым для инициализации по требованию менять naming convention.Это вообще какое-то доведение до абсурда.
Ради того, чтобы не использовать подчёркивание, ты готов назвать две переменных одинаковым именем, различающимся только регистром?
Всё-таки, ко всему надо подходить с умом.
информация не о тех данных, которые хранятся в переменной _state, а информация о самой переменной _state, т.е. это можно отнести к метаданным. И тут подходит вторая цитатаИ точно так же можно сказать про твой вариант, просто в нём информация о переменной передаётся не знаком подчёркивания, а нижним регистром первой буквы.
Ради того, чтобы не использовать подчёркивание, ты готов назвать две переменных одинаковым именем, различающимся только регистром?ващето, это широко распространенная практика. Тебя же не смущает, что имя типа часто вточности совпадает с именем свойства? И не надо извращать мои намерения, я действую в соответствие с общепринятыми рекомендованными создателями платформы naming convention, а не ради "не использовать подчёркивание". Это ж надо так извратить.
Тебя же не смущает, что имя типа часто вточности совпадает с именем свойства?Когда я такое вижу - меня это очень смущает.
И не надо извращать мои намерения, я действую в соответствие с общепринятыми рекомендованными создателями платформы naming conventionТам где-то явно рекомендуется иметь в некоторых случаях две переменные с одинаковыми именами?
И точно так же можно сказать про твой вариант, просто в нём информация о переменной передаётся не знаком подчёркивания, а нижним регистром первой буквы.да это так. Но я не использую префикс, поэтому вот эта цитата уже не подходит к моему варианту
Do not use Hungarian notation.
Hungarian notation is the practice of including a prefix in identifiers to encode some metadata about the parameter, such as the data type of the identifier.
Когда я такое вижу - меня это очень смущает.продолжаем изучение азов языка C#
The following rules outline the naming guidelines for properties:
Consider creating a property with the same name as its underlying type. For example, if you declare a property named Color, the type of the property should likewise be Color. See the example later in this topic.
http://msdn.microsoft.com/en-us/library/ms229045.aspx
Там где-то явно рекомендуется иметь в некоторых случаях две переменные с одинаковыми именами?Во-первых, не одинаковыми, регистр в C# учитывается.
К сожалению, явно майкрософт прописал naming convention только для публичных и протектед конструкций. Для приватных членов остается руководствоваться только уже упомянутыми цитатами
http://msdn.microsoft.com/en-us/library/ms229045.aspx
Для приватных членов остается руководствоваться только уже упомянутыми цитатамину и у Java позаимствовать , там все явно определено.
Do choose easilyreadable identifier names. For example, a property namedHorizontalAlignment is more readable in English thanAlignmentHorizontal.Dofavor readability over brevity. The property name CanScrollHorizontallyis better than ScrollableX (an obscure reference to the X-axis).Do not use underscores, hyphens, or any other nonalphanumeric characters.Do not use Hungarian notation.
я бы еще добавил: Do not use php. Ибо съедает мозг
Do not use Hungarian notation.Hungarian notation is the practice of including a prefix in identifiers to encode some metadata about the parameter, such as the data type of the identifier.Инициализация по требованию - это очень частый паттерн.
Я не согласен с тем, что подчеркивание в имени поля, хранящего состояние - это метаинформация об этом поле (как например, тип и т.п.). Это скорее информация о самом паттерне. Когда вы видите в коде поле, начинающееся с подчеркивания, - значит применяется паттерн Инициализация по требованию.
Разве это не упрощает понимание кода?
Когда вы видите в коде поле, начинающееся с подчеркивания, - значит применяется паттерн Инициализация по требованию.Первый раз слышу такое правило. Пожалуйста, ссылки на авторитетные источники.
Разве это не упрощает понимание кода?
нет
я бы еще добавил: Do not use php. Ибо съедает мозгкстати, это отдельная тема. Кажется, Красин толкал мысль о том, что хороший программист должен знать широкий спектр языков. Может это и так, но видимо выполняется далеко не для всех. В реальности часто проявляется как раз обратное. Человек переходящий на новый язык, не утруждает себя изучением многих мелочей, но, во-первых, некоторые мелочи могут оказаться совсем не мелочами. Во-вторых, мелочи накапливаются, и в итоге код написанный человеком "из другого" языка выглядит ужасным.
Кажется, Кузнецов считал изучивших в качестве своего первого языка программирования бейсик "испорченными" программистами. То, правда, его личное мнение.
очень многие так считают. не только Кузнецов
Я указал это по той причине, что сам так не считаю, но, не имея знакомств с большим числом таких программистов, не могу утверждать это уверенно. А Кузнецов говорит это исходя из своего опыта.
Во-вторых, мелочи накапливаются, и в итоге код написанный человеком "из другого" языка выглядит ужасным.не совсем так. Вначале пытаешься на новом языке программировать как на старом или как на том, который нравится в данный момент. Естественно, получается не очень. Ну а со временем, конечно, всё приходит в норму.
Ну а со временем, конечно, всё приходит в норму.по мои наблюдениям многие останавливаются раньше, и до нормы не доходят.
Во-первых, не одинаковыми, регистр в C# учитывается.Не придирайся к словам. Ясно, что такой код работать будет; речь о том, насколько он понятен.
Но я не использую префикс, поэтому вот эта цитата уже не подходит к моему вариантуБуквоед, бл. Твой извращённый вариант гораздо хуже, чем с префиксом - но ведь буква закона соблюдена!
Кажется, Кузнецов считал изучивших в качестве своего первого языка программирования бейсик "испорченными" программистами.Потому что в бейсике - GoTo
goto даже в java есть зарезервированным словом и что ?
не неси пурги. гото есть почти во всех языках. Но не все они построены на ежесекундном его употреблении
не неси пурги. гото есть почти во всех языках. Но не все они построены на ежесекундном его употребленииЭто я знаю. Но тема-то про code style, а значит это момент несущественный.
Кстати, в ассемблере есть jmp и loop и больше нет ничего, но он же не портит программистов.
гото есть почти во всех языкахЯ говорил, что нету?
Не придирайся к словам. Ясно, что такой код работать будет; речь о том, насколько он понятен.просто, я бы никогда не назвал state и State одинаковыми.
Твой извращённый вариант гораздо хуже
Чем хуже? тем, что для тебя state и State одинаковые? но для многих это не так.
Чем хуже? тем, что для тебя state и State одинаковые?Тем, что state и State похожи гораздо сильнее, чем state и _state. Преимуществ же не видно никаких - кроме того, что _формально_ ты выполняешь гайдлайны, следуешь их букве (продолжая нарушать их дух).
продолжая нарушать их духкакой дух я нарушаю?
В чём, по-твоему, суть рекомендации не использовать подчёркивания в именах переменных? Какие причины этой рекомендации?
Тем, что state и State похожи гораздо сильнее, чем state и _state.Это единственный аргумент в пользу того, что state хуже? Может стоит для каждой переменной генерить GUID и ставить его на место префикса? отличие будет гораздо большее.
Может стоит для каждой переменной генерить GUID и ставить его на место префикса?Не стоит.
1) За GUID-ом теряется реальное имя переменной.
2) Auto-completion-ом будет практически невозможно пользоваться, потому что имена переменных будут начинаться с GUID.
Не стоит.оба пункта подходят и для state против _state
1) За GUID-ом теряется реальное имя переменной.
2) Auto-completion-ом будет практически невозможно пользоваться, потому что имена переменных будут начинаться с GUID.
1) За подчеркиванием теряется (по крайней мере хуже просматривается) реальное имя переменной.
2) пользоваться auto-completion-ом сложнее, кроме имени переменной надо помнить начинается она с подчеркивания или нет. Т.е. для auto-completion нужно помнить и вводить на один символ больше.
За подчеркиванием теряется (по крайней мере хуже просматривается) реальное имя переменной.Подчёркивание занимает меньше места, чем GUID.
пользоваться auto-completion-ом сложнееНе так, как с GUID.
кроме имени переменной надо помнить начинается она с подчеркивания или нет. Т.е. для auto-completion нужно помнить и вводить на один символ больше.Ещё, напомню, исходно речь шла о коде вида:
string _state = null;
public string State
{
if(_state==null)
{
_state=LoadState;
}
return _state;
}
где везде используется state, а _state - только в одном месте.
Кстати, твой auto-completion при нажатии на большую S покажет и state, и State? Или только State?
Напротив, auto-completion не будет находить _state, если специально не искать, и это хорошо.
В чём, по-твоему, суть рекомендации не использовать подчёркивания в именах переменных? Какие причины этой рекомендации?отвечаешь вопросом на вопрос?
Мне нужно уточнить кое-что, прежде чем отвечать на твой вопрос. Тебе в этом что-то не нравится?
Кстати, твой auto-completion при нажатии на большую S покажет и state, и State? Или только State?это настраивается. Я пользуюсь тем, который показывает оба.
Тебе в этом что-то не нравится?да, потому что твой вопрос слишком общего характера, и мне долго формулировать на него полный ответ.
Потому что гораздо легче допустить ошибку в твоём варианте, выбрав не то поле там, где надо использовать State - чем с подчёркиванием в тех трёх расположенных рядом строчках, где оно используется.
ЗЫ: А ещё можно всё заврапить как-то вроде:
static class Util {
public static T LazyGet<T>(Func<T> calculator, ref T field) {
if(field == null) field = calculator;
return field;
}
}
и, вместо четырёх строчек, будет одна:
return Util.LazyGet<string> => LoadState this._state);, с одним упоминанием _state. Если учесть, что она ещё и должна быть расположена не далее, чем в двух-трёх строчках от определения _state, то вероятность ошибиться сводится практически к нулю.
Если же называть их state и State, а intellisense будет показывать оба варианта - ты сможешь ошибиться везде, где используешь State внутри этого класса, а таких мест может быть неограниченно много.
Попробуй ответить хоть как-то. Потому что ответ на этот вопрос - ключевой для дальнейшего обсуждения, без него непонятна твоя точка зрения.
Напротив, auto-completion не будет находить _state, если специально не искать, и это хорошо.Тк это если вам не нужна _state, например, в случае lazy инициализации, да и то не всегда. Но менять naming convention специально для lazy инициализации глупо. Поскольку это увеличивает объем правил в naming convention, если идти по этому пути они просто распухнут и их никто не будет соблюдать. Каждый будет помнить свои правила, и читать друг друга будет сложнее.
К тому же, какой аргумент более весомый
1. калечить имя переменной
2. увеличивается вероятность ошибки при выборе из списка auto-completion
для меня не очевидно.
Для меня читаемость кода стоит на первом месте, относительно сложности написания.
Попробуй ответить хоть как-то. Потому что ответ на этот вопрос - ключевой для дальнейшего обсуждения, без него непонятна твоя точка зрения.минусов от их использования больше, чем плюсов
Но менять naming convention специально для lazy инициализации глупо.Досконально, не задумываясь, следовать каким-то общим гайдлайном, придуманным кем-то довольно левым по отношению к команде разработчиков, даже тогда, когда от этого много вреда и никакой пользы - гораздо более глупо.
Для меня читаемость кода стоит на первом местеЧитаемость кода определяется не только "калеченьем" имени переменной (и это ещё большой вопрос, является ли "_" калеченьем). Когда у тебя две переменные, названия которых отличаются регистром - читаемость гораздо хуже.
Кроме того, читаемость очень тесно связана с модифицируемостью, а модифицируемость от твоего варианта очень сильно страдает. Причём допущенные таким образом ошибки не приведут к 100% фатальному падению программы (не говоря уж о ругани редактора/компилятора а будут приводить к фатальному падению только иногда, когда перед тем, как обратиться к state, не обратились к State - а это ещё хуже. Ладно бы, у state и State были разные типы, а когда они отличаются только значением (да и то - иногда) и регистром - это использование нехороших неявных фич языка. То, что имена переменных чувствительны к регистру - далеко не очевидно с простой житейской точки зрения (как и обратное так что не стоит этим пользоваться в сторону неочевидности (т.е. в языке с чувствительностью регистра заводить state и State, а в языке с нечувствительностью - обращаться к state как к State).
минусов от их использования больше, чем плюсовЭто ты про гайдлайны? Ну и не используй, о чём разговор?
про подчеркивания и т.п.
Кроме того, читаемость очень тесно связана с модифицируемостью, а модифицируемость от твоего варианта очень сильно страдает.чего?
не говоря уж о ругани редактора/компилятораимхо, для ReSharper-а можно ввести атрибут анотации, и написать небольшой плагинчик, который будет следить за тем, чтобы обращение к state было только внутри одного свойства. Думаю, что это займет не более одного дня. Возмоюжно, такое уже есть.
имхо, для ReSharper-а можно ввести атрибут анотации, и написать небольшой плагинчик, который будет следить за тем, чтобы обращение к state было только внутри одного свойства. Думаю, что это займет не более одного дня. Возмоюжно, такое уже есть.Ну и зачем городить велосипед?
про подчеркивания и т.п.Какие минусы от их использования кроме того, что они нарушают гайдлайны?
Потому что гайдлайны - это всего лишь рекомендации, и какие причины таких рекомендаций, ты не сказал.
Заставь дурака Богу молиться, он и лоб расшибётНадеюсь, ты понимаешь, что само по себе слепое следование гайдлайнам без понимания причин, почему они именно такие, во многих случаях - вредно, а не полезно?
Ну и зачем городить велосипед?Это гораздо полезнее, чем ваши извращения над именем переменной. Это гарантированная проверка на отсутвие ошибки до рантайма, а ваша стратегия только уменьшает вероятность ошибки, да и то это только умозрительное заключение, насколько эта вероятность падает в реальных проектах еще не известно.
Надеюсь, ты понимаешь, что само по себе слепое следование гайдлайнам без понимания причин, почему они именно такие, во многих случаях - вредно, а не полезно?Надеюсь ты понимаешь, что
1. исходники не должны быть привязаны к команде разработчиков.
2. разработчики перетекают из команды в команду, и осваение тонкостей naming convention, подобных этой, будет занимать много времени, к тому же разработчику это скушно, а проконтролировать все ли он усвоил сложно.
Твои аргументы против моих в этом треде сводятся к "на вкус и цвет товарищей нет". Для таких ситуаций и сделаны документы от создателей, у которых выделенная роль.
Когда это оправдано, я и сам меняю naming convention, например, в моем проекте Property Expression, название метода состоит из одного подчеркивания "_".
it => it._(_ => _.A001).Add(it._(_ => _.A007
Почему здесь это оправдано. Разработчики языка не реализовали востребованный в реальных проектах принцип Dataflow. В собственной реализацией полноценного синтаксического сахара я ввести не могу, поэтому приходится эмулировать его через метод с именем "_" и такую же переменную.
А ещё можно всё заврапить как-то вродевчера не внимательно посмотрел на твою обертку. Если уж заморачиваться оберткой, тогда пусть обертка полностью скрывает переменную, которая хранит данные
private readonly LazyProxy<string> stateProxy = new LazyProxy<string>
public string State
{
get
{
return stateProxy.GetValue(LoadState);
}
}
...
public class LazyProxy<T> where T : class
{
private T value;
public T GetValue(Func<T> func)
{
if (value == null)
{
value = func;
}
return value;
}
}
P.S. я бы еще перенес Func<T> func из аргумента метода GetValue в аргумент конструктора класса LazyProxy. Тогда переменную stateProxy надо будет инициализировать в конструкторе класса, для меня это не вызывает никаких проблем, но вы же начнете считать строчки, и их окажется на две больше, поэтому я привел этот вариант в качестве демонстрации.
применение такого паттерна, гораздо эффективнее против тех ошибок, за которые вы боялись, чем извращаться над naming convention.
но вы же начнете считать строчки, и их окажется на две больше, поэтому я привел этот вариант в качестве демонстрации.конечно, и строчки, и скорость, и память.
proxy - скорее надо struct-ом делать
у ленивой функции еще бывают 2-3 параметра - поэтому в конструктор не перенесешь.
и скорость, и память.даже MS не заморачивается на это, создает по несколько EntityRef для каждого инстанса data-сущности в LINQ to SQL.
у ленивой функции еще бывают 2-3 параметра - поэтому в конструктор не перенесешь.
могу ошибаться, но в внутри гетора State { get {...} } доступно ровно столько же параметров сколько и в конструкторе.
могу ошибаться, но в внутри гетора State { get {...} } доступно ровно столько же параметров сколько и в конструкторе.так ты оказывается вообще про конструктор класса говоришь...
нет, это не вариант, т.к. атомарность ухудшается.
т.к. атомарность ухудшается.а что это такое? то что строчки кода рядом находятся? А так ли уж это важно при нормальной навигации по коду? Модификатор readonly будет гарантировать, что инициализация stateProxy идет только в конструкторе.
Почему я хочу передавать параметр в конструкторе, чтобы явно показать, что lazy инициализация идет через один метод LoadState, а то можно вызвать stateProxy.GetValue(LoadState а потом stateProxy.GetValue(LoadState2).
А так ли уж это важно при нормальной навигации по коду?Как быть с масштабируемостью? Что будет при увеличении кол-ва lazy свойств до 10? 20? 100?
Их в конструкторе все определять?
Что будет при увеличении кол-ва lazy свойств до 10? 20? 100?да, в конструкторе. Не вижу никаких проблем при нормальной навигации (повторяюсь ).
Их в конструкторе все определять?
Как быть с масштабируемостью? Что будет при увеличении кол-ва lazy свойств до 10? 20? 100?В таком случае используют другие механизмы написания кода. Если у объекта десятки lazy свойств, то выписывать их всех руками никто не будет. Вместо этого можно, например, применять паттерн proxy, реализуя его с помощью NMock2 или DynamicProxy из Castle.
Оставить комментарий
kokoc88
Тем временем я нашёл аргумент в пользу подчёркиваний. Оказывается, некоторые разработчики передают в методы переменные, названные как локальные поля. При этом они не пользуются ReSharper-ом или другими средствами, спасающими от глупостей.