Очередная статья о C# 7 заставила задуматься: а в чём профит от non-null типов? То, что null — это ошибка, очевидно. Но разве можно не намокнуть, "запретив дождь"?!
Ведь null — это и есть индикатор, что что-то пошлó не так! Просто "взрыв на присвоении null" ничего не даст — нужно смотреть глубже в алгоритм и делать больше проверок/диагностик, чтобы null не вылезал, когда уже слишком поздно. Другими словами, non-null типы просто бесполезны!
Если вы поняли мою идею (или её ошибочность), отпишитесь — интересная тема.
Здравствуйте, Kolesiki, Вы писали:
K>Очередная статья о C# 7 заставила задуматься: а в чём профит от non-null типов? То, что null — это ошибка, очевидно. Но разве можно не намокнуть, "запретив дождь"?!
Кэп: в api прописываешь, где конкретно ожидаешь null, компилятор предупреждает о возможном null ref exception при попытке обратиться к nullable value без проверки на null.
Для всего остального компилятор предупреждает о попытке запихнуть null куда не надо.
Включаем конкретные предупреждения в список threat as errors — получаем на порядок меньше шансов отхватить null где не надо.
Разумеется, от намеренного головотяпства со взломом оно не спасёт, но общая температура по больнице должна слегка выправиться.
А, да, статью закопать обратно. Автор ещё дольше бы спал — non-null ещё летом (или в конце весны? лень проверять) в восьмой шарп перенесли.
А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет?
Здравствуйте, aloch, Вы писали:
A>Здравствуйте, Kolesiki, Вы писали:
A> То, что null — это ошибка, очевидно.
A>А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет?
Можно для каждого класcа, по аналогии со String создавать пустой Empty
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Kolesiki, Вы писали:
K>Ведь null — это и есть индикатор, что что-то пошлó не так! Просто "взрыв на присвоении null" ничего не даст — нужно смотреть глубже в алгоритм и делать больше проверок/диагностик, чтобы null не вылезал, когда уже слишком поздно. Другими словами, non-null типы просто бесполезны!
Тут прикол в том, что "взрыва" быть не должно — проверка на null должна происходить статически. То есть на этапе выполнения сюрпризов не должно быть. Примерно так же, как сейчас нельзя присвоить null в int. Но это в теории, как там хотят в си-краше сделать, я хз.
Здравствуйте, Kolesiki, Вы писали:
K>То, что null — это ошибка, очевидно.
Вот на этом месте надо включить мозг.
Тысячи мест в самом .NET FW и миллионы в остальном коде, где null — корректное значение, в остальных случаях ошибка.
K>Ведь null — это и есть индикатор, что что-то пошлó не так! Просто "взрыв на присвоении null" ничего не даст — нужно смотреть глубже в алгоритм и делать больше проверок/диагностик, чтобы null не вылезал, когда уже слишком поздно.
А с другой стороны в методах уменьшится количество проверок на null, это еще и немного скорость работы увеличит, так как будет контролироваться компилятором и не рантаймом.
Причем в 90+% случаев в алгоритме невозможно появление null, поэтому легко заменить nullable на non-nullable тип. В оставшихся 10% компилятор заставит вас написать код, который явно обрабатывает null, что лучше, чем получить ошибку в рантайме.
Здравствуйте, Serginio1, Вы писали:
A>> То, что null — это ошибка, очевидно. A>>А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет? S> Можно для каждого класcа, по аналогии со String создавать пустой Empty
Тогда, если забыть проинициализировать, программа вместно честного падения будет продолжать работать и где-то совсем не там выдаст неправильный результат. И ищи потом концы...
Здравствуйте, vmpire, Вы писали:
V>Здравствуйте, Serginio1, Вы писали:
A>>> То, что null — это ошибка, очевидно. A>>>А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет? S>> Можно для каждого класcа, по аналогии со String создавать пустой Empty V>Тогда, если забыть проинициализировать, программа вместно честного падения будет продолжать работать и где-то совсем не там выдаст неправильный результат. И ищи потом концы...
Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S> Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет.
И в итоге ошибка "забыли заполнить поле" молча проходит тесты и выстреливает в продакшне. Прелестно.
На эти грабли уже наступили в VB. Закончилось тройкой из Null / Empty / Nothing. Если понравилось, можно проголосовать за вот тут.
Здравствуйте, Serginio1, Вы писали:
A>>>> То, что null — это ошибка, очевидно. A>>>>А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет? S>>> Можно для каждого класcа, по аналогии со String создавать пустой Empty V>>Тогда, если забыть проинициализировать, программа вместно честного падения будет продолжать работать и где-то совсем не там выдаст неправильный результат. И ищи потом концы... S> Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет.
В том то и проблема.
Если nullable тип не проинициализирован, а проверки нет — всё упадёт достаточно быстро и будет легко найти причину.
Если не-nullable тип не проинициализирован, а проверки нет — всё моет и вообще не упасть а вылезет вообще не там.
Ну а если для не-nullable типов везде нужно ставить проверки (которые автоматически есть для nullable), то в чём польза-то?
Здравствуйте, Sinix, Вы писали:
S>Здравствуйте, Serginio1, Вы писали:
S>> Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет.
S>И в итоге ошибка "забыли заполнить поле" молча проходит тесты и выстреливает в продакшне. Прелестно.
Но при NotNull такого не будет. S>На эти грабли уже наступили в VB. Закончилось тройкой из Null / Empty / Nothing. Если понравилось, можно проголосовать за вот тут.
Для иммутабельных типов NotNull считаю приемлен.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Kolesiki, Вы писали:
K>Очередная статья о C# 7 заставила задуматься: а в чём профит от non-null типов? То, что null — это ошибка, очевидно. Но разве можно не намокнуть, "запретив дождь"?! K>Ведь null — это и есть индикатор, что что-то пошлó не так! Просто "взрыв на присвоении null" ничего не даст — нужно смотреть глубже в алгоритм и делать больше проверок/диагностик, чтобы null не вылезал, когда уже слишком поздно. Другими словами, non-null типы просто бесполезны! K>Если вы поняли мою идею (или её ошибочность), отпишитесь — интересная тема.
Подобное есть в Котлине, при чем по умолчанию. Может поискать что они на это говорят?
Здравствуйте, vmpire, Вы писали:
V>Здравствуйте, Serginio1, Вы писали:
A>>>>> То, что null — это ошибка, очевидно. A>>>>>А почему? Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет? S>>>> Можно для каждого класcа, по аналогии со String создавать пустой Empty V>>>Тогда, если забыть проинициализировать, программа вместно честного падения будет продолжать работать и где-то совсем не там выдаст неправильный результат. И ищи потом концы... S>> Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет. V>В том то и проблема. V>Если nullable тип не проинициализирован, а проверки нет — всё упадёт достаточно быстро и будет легко найти причину.
То, что я предложил касается иммутабельных типов. Для них можно заводить синглетоны. И в классе отрабатывать эти Empty
V>Если не-nullable тип не проинициализирован, а проверки нет — всё моет и вообще не упасть а вылезет вообще не там. V>Ну а если для не-nullable типов везде нужно ставить проверки (которые автоматически есть для nullable), то в чём польза-то?
Не вижу разницы на сравнение между Null или Empty в качестве сравнения. А вот у Empty можно вызывать методы, свойства и тд которые по умолчанию.
Но опять это касается иммутабельных типов.
и солнце б утром не вставало, когда бы не было меня
Здравствуйте, Serginio1, Вы писали:
S>>И в итоге ошибка "забыли заполнить поле" молча проходит тесты и выстреливает в продакшне. Прелестно. S> Но при NotNull такого не будет.
Эмм, мы всё ещё про это говорим:
A>Или при запуске программы нужно создать все (даже в данный момент не нужные) объекты, которые потом присвоить всем ссылкам в программе? И сколько это будет запускаться и сколько памяти сожрет?
Можно для каждого класcа, по аналогии со String создавать пустой Empty
?
Ну вот оно конечно от null избавит, но лечение хуже болезни будет — отличить "забыли заполнить" от "пустое значение" теперь низзя.
Правильный вариант тут — явно помечать поле как "может быть null" и отдать остальное компилятору на откуп.
Здравствуйте, Serginio1, Вы писали:
S>>> Ну ты же работаешь со String.Empty. Можешь проверить на String.Empty, а можешь сразу применить IndexOf. На String.Empty исключения не будет. V>>В том то и проблема. V>>Если nullable тип не проинициализирован, а проверки нет — всё упадёт достаточно быстро и будет легко найти причину.
S> То, что я предложил касается иммутабельных типов. Для них можно заводить синглетоны. И в классе отрабатывать эти Empty
Ну так это ещё код который нужно написать и не забыть
V>>Если не-nullable тип не проинициализирован, а проверки нет — всё моет и вообще не упасть а вылезет вообще не там. V>>Ну а если для не-nullable типов везде нужно ставить проверки (которые автоматически есть для nullable), то в чём польза-то?
S> Не вижу разницы на сравнение между Null или Empty в качестве сравнения. А вот у Empty можно вызывать методы, свойства и тд которые по умолчанию. S>Но опять это касается иммутабельных типов.
Разница в том, что для nullable никаких проверок писать не надо, оно и так упадёт
Здравствуйте, Sinix, Вы писали:
S>Ну вот оно конечно от null избавит, но лечение хуже болезни будет — отличить "забыли заполнить" от "пустое значение" теперь низзя.
Правильный вариант — не давать использовать переменную, значение которой не было установлено хотя бы по одному пути управления.
Здравствуйте, hardcase, Вы писали:
H>Правильный вариант — не давать использовать переменную, значение которой не было установлено хотя бы по одному пути управления.
Не работает такой подход без кардинально ломающих изменений, получится два "недопустимых" значения — null и empty.
Breaking changes оставляем любителям, остаётся только один вариант: научить компилятор нормально работать с null и на этом перестать изобретать что-то ещё.
Здравствуйте, Sinix, Вы писали:
K>> а в чём профит от non-null типов?
S>Кэп: в api прописываешь, где конкретно ожидаешь null, компилятор предупреждает о возможном null
Увы, бестолковый пример к статье как раз и не иллюстрирует подобного профита. И насколько я понял, "улучшение" состоит ровно в обратном: указывать, где тип НЕ может быть null.
Ну ОК, возьмём гипотетический пример:
И тут на ровном месте имеем проблему:
1. Если даже мы "интуитивно уверены", что null принципиально не может возвратиться из OldFun, никого это не спасёт — либо превращай non-null error в warning, либо уродуй код отключением предупреждений, либо выноси обращение к OldFun в отдельную переменную с проверкой, но в любом случае получаешь кодокаку.
2. Допустим, OldFun — чужая функция и нет возможности указать, что она всегда возвращает non-null. И это 100% 3-rd party библиотек. Значит введением non-null, мы сразу огребаем от всего легаси кода. А если этот non-null введут в сам дотнет?!
3. Null — он как бы и проблема, но где это критично, можно обойтись более строгим кодом с проверками. А где некритично, да и нехай вылазит NPE — сами и виноваты!
Я всё это к чему: к инверсии зависимостей Не должна функция, которая является сторонней к нашему коду, диктовать нам как её вызывать. Наоборот, мы контролируем, где и как мы хотим нарваться на грабли. Скажем, есть глубоко вложенные вызовы всякой фигни, но ловим проблемы только на верхнем уровне. А теперь представь, самый вложенный метод вдруг закочевряжится "хочу не нулл!". Что, курочить весь код ради Math.sqrt??
Вощим, студенческих идей витает много, но не все себе представляют порядок проблем. Нельзя "выключить дождь", надо заставить себя сделать более качественный зонтик.
Ну и как итог, зачем курочить язык (и впоследствии чужой код), если можно сделать сторонний анализатор, который сделает более глубокие проверки (как у PVS Studio) за более длительное время, но зато даст более качественный результат?
Здравствуйте, Sinix, Вы писали:
S>Кэп: в api прописываешь, где конкретно ожидаешь null...
Да, и ещё один важный момент: искушение скидывать проверки на других. Тысячи библиотековаятелей с радостью нафигачат fun(Class! obj), лишь бы писать поменьше! Это превратит разработку в кошмар из проверок на пустом месте.
Конечно, можно и не обращать внимания на warnings, но какой тогда смысл их иметь?
Здравствуйте, Kolesiki, Вы писали:
K>Увы, бестолковый пример к статье как раз и не иллюстрирует подобного профита.
Там вся статья бестолковая
Конкретно про nullables написано по мотивам творческого перепева ранних proposals.
Нынешний вариант выглядит вот так, прочитать стоит как минимум раздел "Opting In and Opting Out". Если есть желание обсуждать — прочитать лучше и всё остальное, там куча моментов уже поднималась.
K>И тут на ровном месте имеем проблему:
Нет никакой проблемы, для каждой библиотеки assumed nullability выставляется отдельно. Если совсем невтерпёж, то всегда можно пойти по следам решарпера и прикрутить external annotations: размечать public API nullability через аннотации в xml-файлике. В принципе, его можно даже автоматом генерить, flow analysis по il не сильно сложнее его же по ast рослина.
Больше деталей будет после текущего релиза, сейчас им заняты.
Здравствуйте, Kolesiki, Вы писали:
K>Да, и ещё один важный момент: искушение скидывать проверки на других. Тысячи библиотековаятелей с радостью нафигачат fun(Class! obj), лишь бы писать поменьше! Это превратит разработку в кошмар из проверок на пустом месте. K>Конечно, можно и не обращать внимания на warnings, но какой тогда смысл их иметь?
Здесь пахнет двойными стандартами. Тебе не нравится что автор библиотеки скидывает ответственность на тебя и хочешь спихнуть её на автора библиотеки.
К слову, а с переносом в C#8 не было планов по созданию белых списков для Nullable-аргументов?
Волшебной галки на проекте, которая считает все, условно говоря, String по-умолчанию не нулябельными и требует явного указания String? для возможности передать в неё Null?
Здравствуйте, LWhisper, Вы писали:
LW>К слову, а с переносом в C#8 не было планов по созданию белых списков для Nullable-аргументов? LW>Волшебной галки на проекте, которая считает все, условно говоря, String по-умолчанию не нулябельными и требует явного указания String? для возможности передать в неё Null?
...
It is possible to apply the following attribute to a declaration itself in order to opt in or opt out all consumers from nullability warnings originating from the declaration
Здравствуйте, LWhisper, Вы писали:
LW>Здесь пахнет двойными стандартами. Тебе не нравится что автор библиотеки скидывает ответственность на тебя и хочешь спихнуть её на автора библиотеки.
Автор библиотеки и так ОБЯЗАН отвечать за свой код — что код по кр. мере не взрывается на некорректных данных (как половина дотнета. Пример — похабнейшая реализация string.Substring).
Что я пытаюсь избежать, так это ещё и в своём коде городить чужие проверки только потому, что ленивая задница поставила [NonNull] атрибут. Спасибо, Синикс успокоил — можно подавлять эти капризы на уровне сборки.
Я вот перечитал трэд и всё ещё считаю, что никого этот NonNull не спасёт — этих предупреждений будет СЛИШКОМ МНОГО, чтобы честно на них реагировать.
Кроме того, всё зависит от задач — где-то и null — вполне допустимый возврат из функции, который в критичном месте можно проверить.
Здравствуйте, Kolesiki, Вы писали:
K>Я вот перечитал трэд и всё ещё считаю, что никого этот NonNull не спасёт — этих предупреждений будет СЛИШКОМ МНОГО, чтобы честно на них реагировать.
Если сделать правильно, то никаких предупреждений не будет, будет ошибка компиляции в том месте, где идет вызов потенциально нуллабельного объекта.
public class MyObj
{
public void Go()
{
// ...
}
}
public class MyClass
{
private MyObj Foo()
{
// ...
}
private [NotNull] MyObj Bar()
{
// ...
}
public void Test()
{
var fooResult = Foo();
// ошибка компиляции! fooResult может быть равно null
//fooResult.Go();
// а вот так - работаетif (fooResult != null)
fooResult.Go();
var barResult = Bar();
// работает без всяких проверок, так как barResult гарантированно не равен null
barResult.Go();
}
}
}
Вообще по уму надо бы конечно инвертировать — атрибут должен быть не NotNull, а Null. А not null должен быть у всех параметров по умолчанию. Короче так же, как и с value-типами.
Для компиляции старого говнокода ввести ключ -crapcode, который будет компилять в старом режиме.
Однако что-то мне подсказывает, что сделают через жопу и действительно будет убогое говно с предупреждениями (каким сейчас являются контракты).
Здравствуйте, AlexRK, Вы писали:
ARK>Вообще по уму надо бы конечно инвертировать — атрибут должен быть не NotNull, а Null. А not null должен быть у всех параметров по умолчанию. Короче так же, как и с value-типами.
Именно так оно и будет работать. Только вместо атрибута — синтаксический сахар с "MyObj?".
ARK>Однако что-то мне подсказывает, что сделают через жопу и действительно будет убогое говно с предупреждениями (каким сейчас являются контракты).
Не сделают, выше были ссылки на спецификацию.
Здравствуйте, Kolesiki, Вы писали:
K>Ведь null — это и есть индикатор, что что-то пошлó не так! Просто "взрыв на присвоении null" ничего не даст — нужно смотреть глубже в алгоритм и делать больше проверок/диагностик, чтобы null не вылезал, когда уже слишком поздно. Другими словами, non-null типы просто бесполезны! K>Если вы поняли мою идею (или её ошибочность), отпишитесь — интересная тема.
Идея такая. Представь себя на месте юзера. Вот пользуешься ты некоторой программой, попытался создать в ней новый документ и вдруг получил NullReferenceException. Что его вызвало — непонятно. Да и разработчики без дампа (или хотя бы stack trace) мало чем смогут помочь. Если бы вместо этого программа выдала "Exception: template file does not exist", ты бы сразу смекнул "наверное, это была прохая идея удалить normal.dot, чтобы освободить 1 килобайт на диске".
Теперь давай смотреть, почему вместо осмысленного exception-а вылез обычный NullReferenence. В 99% случаев паттерн будет такой:
SomeClass LoadSomething()
{
if(something)
return null;
}
//...
SomeClass obj = LoadSomething();
obj.DoSomething(); // <== Вот тебе бабушка и NullReferenceException
Почему это происходит? Заговор программистов? Попытка свергнуть режим? Тайное общество почитателей Null-а?
Нет, все проще. Человек, который писал LoadSomething(), подумал, что проверку на null сделают в вызывающем коде, а человек, который писал вызов, подумал, что LoadSomething() сам бросит осмысленный Exception.
Соответственно, что поменяется с приходом Non-nullable? LoadSomething() можно будет объявить как non-nullable, тогда попытка вернуть из него null словится на этапе компиляции. Соответственно, человек, добавивший проверку на if(something) это увидит и быстро поправит:
SomeClass! LoadSomething()
{
if(something)
throw new Exception("Something happened. You better run.");
}
С другой стороны, если в проекте договорятся что LoadSomething() сама ничего не бросает и возвращает null, то ее оставят как есть и тогда компилятор сможет с полным правом выдать warning, что вызывать obj.Something() без проверки obj на null нехорошо.
Как-то так.
P.S. Кстати, подобное давно реализовано в тех же Code Contracts от MS, но они за пределами research особо не популярны.
Здравствуйте, bazis1, Вы писали:
B>P.S. Кстати, подобное давно реализовано в тех же Code Contracts от MS, но они за пределами research особо не популярны.
Подобное реализовано в решарпере. А CodeContracts копает несколько глубже — статическим анализом пытается устранить рантайм проверки. Но качество реализации — увы, увы.
... << RSDN@Home 1.0.0 alpha 5 rev. 0 on Windows 8 6.2.9200.0>>
K>Если вы поняли мою идею (или её ошибочность), отпишитесь — интересная тема.
Основная мысль в этой теме заключается в том что очень часто null используется в тех случаях когда вызывающему коду надо вернуть признак того что значения нету. Именно в этом случае использовать null не кошерно так как null в данном случае является implicit контрактом, т.е. возврат null вполне ожидаемая ситуация, но клиент об этом не знает так как явно это в контракте прописать невозможно.
Здравствуйте, AndrewVK, Вы писали:
ARK>>Вообще по уму надо бы конечно инвертировать — атрибут должен быть не NotNull, а Null.
AVK>По уму должно быть и то и то — и NotNull, и CanBeNull.
Здравствуйте, AndrewVK, Вы писали:
ARK>>Нет, NotNull не нужен.
AVK>Обоснуешь?
Это лишняя сущность, без которой можно обойтись в 100% случаев. Ее присутствие только вносит путаницу. Она не просто не нужна, она вредна. Если, конечно, разработчики не поставили себе цель превратить C# в огромную кучу мусора а-ля С++ (к чему, впрочем, он и так уверенно идет).
считаю, что нужно добавить значение Everything или God, это бы было в русле поддержки православия,
а так же более эффективно использовать два бита при помощи "семантического тензора".
Здравствуйте, AndrewVK, Вы писали:
AVK>Здравствуйте, bazis1, Вы писали:
B>>P.S. Кстати, подобное давно реализовано в тех же Code Contracts от MS, но они за пределами research особо не популярны.
AVK>Подобное реализовано в решарпере. А CodeContracts копает несколько глубже — статическим анализом пытается устранить рантайм проверки. Но качество реализации — увы, увы.
В CodeContracts в довесок еще и рантайм проверки идут. Правда непонятка чем это лучше, чем скажем Debug.Assert(something != null);
Здравствуйте, bazis1, Вы писали:
B>Здравствуйте, Kolesiki, Вы писали:
B>Теперь давай смотреть, почему вместо осмысленного exception-а вылез обычный NullReferenence. В 99% случаев паттерн будет такой: B>
B>P.S. Кстати, подобное давно реализовано в тех же Code Contracts от MS, но они за пределами research особо не популярны.
А меня вот запрягли эти контракты везде использовать. Был у меня TL, ярый джавист в третем поколении. Вот он прожить не мог, чтобы не ткнуть кого-то носом, если аннотация @Nullable или @NotNull не поставлена в Java коде. Начали мы писать наконец все на нативе к 8-ой версии продукта, и тут то мне и пришлось эти контракты сплошь и рядом тулить.
Кстати пример немного надуман, хотя действительно демонстрирует на пальцах суть. null обычно вылезает в не-инициализированных свойствах и полях. ТС должен знать, что для каждого объекта-члена-класса — дефолтовое значение=null. Вот тут обычно и вся засада. То список забыл создать, то какой-то объект. И если внутри метода вылезет error — вроде низзя без инициализации юзать переменную, то по неведомым причинам для полей и свойств такого компилер не умеет.
А есть еще библиотеки, написанные индусами, вроде HtmlAgility Pack, где вместо вброса эксепшена — лови null как результат метода.
Любой бывалый разработчик подтвердит — NullReferenceException (сокращенно NLP) — самая распространенная ошибка в любой проге. Так что давно пора эту фичу вносить.
Здравствуйте, licedey, Вы писали:
L>В CodeContracts в довесок еще и рантайм проверки идут. Правда непонятка чем это лучше, чем скажем Debug.Assert(something != null);
Оно там не само по себе, а в комплекте. Где удается устранить — там устраняется, где не удается — остается рантайм проверка.
Здравствуйте, licedey, Вы писали:
L>Любой бывалый разработчик подтвердит — NullReferenceException (сокращенно NLP) — самая распространенная ошибка в любой проге. Так что давно пора эту фичу вносить.
Ну вот не знаю... NRE — ошибка частая, но по моей практике в 99% случаях она не от того, что кто-то где-то забыл инициализировать, а от того, что какой-нибудь метод вернул null.
Либо это свой метод, где просто забыли, что может быть и null, либо библиотечный, где по незнанию null иногда не ожидают (типа, Directory.GetDirectoryName).
Вот на возвращаемые значения аннотаия [NotNull] с предупреждением компилятора бы не помешала (хоть и не спасла бы).
А какие-то средства языка или типы специально для этого — не нужно, будет только больше путаницы.
Здравствуйте, bazis1, Вы писали:
B>Идея такая. Представь себя на месте юзера. Вот пользуешься ты некоторой программой, попытался создать в ней новый документ и вдруг получил NullReferenceException. Что его вызвало — непонятно. Да и разработчики без дампа (или хотя бы stack trace) мало чем смогут помочь. Если бы вместо этого программа выдала "Exception: template file does not exist", ты бы сразу смекнул "наверное, это была прохая идея удалить normal.dot, чтобы освободить 1 килобайт на диске".
Угу, а потом тут же приходят аналитики и верхние менеджеры, которые говорят, что "почему это у вас пользователю показываются технические сообщения? Это нехорошо. Это не обязанность пользователя читать такие сообщения".
И после этого программа начинает вместо этого выдавать: "Программа сделала что-то нехорошее и на всякий случай будет закрыта, позовите администратора, он разберётся". А администратор и сам ничего понять не может. так как сообщение ни о чём, а логов нормальных нет. Либо они есть, но где-нибудь на сервере, где другой администратор и вообще другая организация.
В общем, это к тому, что для конечного пользователя всё равно ничего не поменяется.
Здравствуйте, vmpire, Вы писали:
V>Вот на возвращаемые значения аннотаия [NotNull] с предупреждением компилятора бы не помешала (хоть и не спасла бы). V>А какие-то средства языка или типы специально для этого — не нужно, будет только больше путаницы.
Вот в таком виде мне это нравится намного больше!
Вместо загромождения кода "атрибутами для бестолковых индусов", будет две вещи: [NotNull] для возвращаемых значений + компилятор будет проверять, что переменная получает non-null инициализацию перед использованием.
В моей практике я весьма редко огребаю NRE, чаще капризничают конструкторы с неправильными аргументами.
К слову, упомянутая string.Substring — пример, за который можно увольнять практически сразу — какая-то бестолочь вместо пары проверок выхода за границы И КОРРЕКЦИИ ГРАНИЦ, предпочла капризно бросаться иксепшенами, портя кровь практически 100% разработчиков. Пример:
var s = UserInput();
var FirstTwoLetters = s.Substring(0, 2);
if (FirstTwoLetters == "RU") ...
Вот скажите, ну не всё равно, ЧТО там ввёл юзер и какой длины? Важно то, что даже если он ввёл что-то некорректное, мы УМЕЕМ обрабатывать этот случай. Сейчас же ты, вместо бизнес задач, вынужден танцевать вокруг идиота, писавшего substring, чтоб не дай бог ты не запросил длину больше, чем строка! Катастрофа, полундра, собирайте весь коллектив, будем разбирать, зачем Володька сбрил усы!
Это как раз пример того, чего мы ДОЛЖНЫ избежать, занимаясь non-null магией — чтобы юзерский код не превращался в месконечную мешанину проверок там, где их спокойно можно опустить.