S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов S>
S>var x = Method1().Method2().Method3().Method4();
S>
S>так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x".
Re[5]: Optional Value. Уменьшение количества null reference-
Все не так просто.
На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1).
А TestV2 действительно закончит вычисления при получении null-а.
Re[6]: Optional Value. Уменьшение количества null reference-
Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing.
S>Все не так просто. S>На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1). S>А TestV2 действительно закончит вычисления при получении null-а.
А зачем считать количество заходов в метод?
S>... В MethodX он не зайдет...
И это главное .
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing.
А для чего тебе тогда SelectMany?
S>>Все не так просто. S>>На самом деле твой код, как и мой в TestV1 не прекратит вычисления при получении null-а. В MethodX он не зайдет, но ProcessValue будет вызван столько раз, сколько написано (то же касается SelectMany из TestV1). S>>А TestV2 действительно закончит вычисления при получении null-а. AP>А зачем считать количество заходов в метод?
S>>... В MethodX он не зайдет... AP>И это главное .
Когда делали Query синтакс, тоже так посчитали. А по-моему это лажа, заходить в методы, которые не учавствуют в вычислениях.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
AP>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>А для чего тебе тогда SelectMany?
Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание.
При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... .
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>>А для чего тебе тогда SelectMany? AP>Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание.
Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией.
AP>При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... .
Т.е. фактически bind в map? Хотел всех запутать?
Re[11]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
AP>>>>Во-первых, я полагал, что все понимают, что при переходе на OptionalVallue null-ы надо заменять на Nothing. S>>>А для чего тебе тогда SelectMany? AP>>Второй из перегруженных методов SelectMany нужен для query comprehension syntax. А первый вводился уже в дополнение, для полной аналогии с LINQ. В принципе, его можно убрать. Спасибо за замечание. S>Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией.
Метод нужен, вопрос лишь в его имени и в перегрузке с другими.
AP>>При всем при этом разноименные методы SelectMany и Select часто менее удобны, чем одноименные методы с такими же сигнатурой и смыслом, поэтому есть два метода ProcessValue. Вариант без ProcessValue и переименование первого SelectMany в Select тоже рассматривался ... . S>Т.е. фактически bind в map? Хотел всех запутать?
Монады монадами, а c OptionalValue удобнее работать через одноименные методы. Из примера выше:
var x = Method1()
.ProcessValue(_ => _.Method2())
.ProcessValue(_ => _.Method3())
.ProcessValue(_ => _.Method4());
Здесь любой из методов MethodX может возвращать как T так и IOptionalValue<T> запись от этого не меняется. И это классно .
Re[12]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Странно, что тебе оказался не нужен класический монадный bind (>>=), а сгодился его странноватый гибрид с проекцией. AP>Метод нужен, вопрос лишь в его имени и в перегрузке с другими.
Я привык отождествлять деятельность метода с названием. Если я знаю что короткий SelectMany это bind, а Select — это map, то любые перемены будут мешать.
S>>Т.е. фактически bind в map? Хотел всех запутать? AP>Монады монадами, а c OptionalValue удобнее работать через одноименные методы. Из примера выше: AP>
Здесь любой из методов MethodX может возвращать как T так и IOptionalValue<T> запись от этого не меняется. И это классно .
Не вижу ничего классного. Перемешаны монадные bind-ы с функторами, визуально не отличить что где.
Но самое что интересное, для такой записи не нужны OptionalValue<T>.
static TResult ProcessValue<T, TResult>(this T value, Func<T, TResult> func)
where T : class
where TResult : class
{
return (value != null) ? func(value) : default(TResult);
}
Re[14]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>А на деле не нужна. AP>>>Ковариантность нужна! Там где обычный полиморфизм + option логика = получаем необходимость ковариантности. G>>Бред же. AP>В чем заключается бред, объяснить можешь?
В том что необходимости ковариантности нету. Вообще вариантность заменяется обычным приведением типа.
G>>>>Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками. AP>>>Прописывать ковариантность ручками для option логики непозволительный синтаксический оверхед. G>>Счегобы? Ты даже не смог пример привести где ковариантность была тебе необходима. AP>Не ври. Я не увидел зачем мне напрягаться. Пример потребует некоторых временных затрат. А ты опять не поймешь суть и прицепишься к несущественным моментам. Поэтому углубляться здесь на форуме в кастомные задачи я смысла не вижу. Если, действительно, есть желание, приходи к нам в офис, я тебе покажу код с моего экрана, а потом поговорим по коду.
Запости код сюда и поговорим здесь. А то пока только голословные утверждения о необходимости ковариантности.
Re[4]: Optional Value. Уменьшение количества null reference-
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива. Можно показать мне, как классно будет записан вызов S>
S>var x = Method1().Method2().Method3().Method4();
S>
S>так, чтобы в случае возврата null из любого из методов вместо NRE мы получили null в x?
var x = from x1 in Method1().ToOption()
from x2 in x1.Method2().ToOption()
from x3 in x2.Method3().ToOption()
select x3.Method4();
Естественно куча ифов, как выше — это самый простой случай частичных вычислений. Option<T> позволяет не только чуть более лаконично описывать это безобразие, но и декомпозировать его.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Стесняюсь показаться ретроградом, но имхо этот "водопроводный" код менее многословен и более понятен, чем предложенная альтернатива.
Монада List (Linq 2 Objects) относится к циклам определенного вида, примерно как монада Maybe (Option) к ифам определенного вида. При грамотном использовании позволяет сделать код более наглядным и не прятать логику под тоннами управляющих конструкций.
Re[13]: Optional Value. Уменьшение количества null reference
Здравствуйте, samius, Вы писали:
S>Я привык отождествлять деятельность метода с названием.
Это хорошо.
S>Если я знаю что короткий SelectMany это bind, а Select — это map, то любые перемены будут мешать.
А тут как раз идет отождествление названия с названием.
S>Не вижу ничего классного. Перемешаны монадные bind-ы с функторами, визуально не отличить что где.
Попробуй оторваться на минутку от общих монад и подумать над частным вопросом опциональных значений.
S>Но самое что интересное, для такой записи не нужны OptionalValue<T>.
Ага, я это знаю . Только остается вопрос, когда такой записью пользоваться? Для всех переменных? Нет, спасибо, не буду.
OptionalValue как раз и служит для разделение опциональных и не опциональных переменных. Соответственно, для первых применяем такую запись, а для вторых обычную. А какой будет переменная T или IOptionalValue<T> определяет поставщик переменной. Если мы знаем, что поставщик соблюдает это правило, то для T можно не беспокоиться об NRE. Если поставщик не соблюдает это правило, то все как обычно, т.е. хреново: писать или не писать if, если писать, то, что внутри этого if-а делать и т.д. Глупость заключается в том, чтобы создавать эту хреновую ситуацию и в случае, если вы сами являетесь тем поставщиком.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>>>Это замечание незначительно само по себе, G>>>>>Да ну? Сломать контракт это фигня? AP>>>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>>> AP>>Что тебя так рассмешило? G>То что у тебя нет контракта.
G>>>... а все вместе — нет. AP>>Код в студию.
G>Держи
G>
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>>>>Это замечание незначительно само по себе, G>>>>>>Да ну? Сломать контракт это фигня? AP>>>>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>>>> AP>>>Что тебя так рассмешило? G>>То что у тебя нет контракта.
G>>>>... а все вместе — нет. AP>>>Код в студию.
G>>Держи
G>>
AP>нету. Поэтому в этой ветке ты молча слил, я правильно понимаю?
Не веди себя как дите.
При такой реализации IOptionalValue метода HasValue вернет false, а GetValue не бросит исключение. Я еще не проверял как у тебя Linq в таком случае заработает.
Это и есть контракт, который у тебя не энфорсится никак.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали: AP>Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x".
Ну давайте перепишем:
Type1 x = null;
var x1 = Method1();
if(x1 != null)
{
var x2 = x1.Method2();
if(x2 != null)
{
var x3 = x2.Method3();
if(x3 != null)
x = x3.Method4();
}
}
Это что-то принципиально поменяет?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
AP>>Для честного сравнения надо сначала переписать "водопроводный" код "так, чтобы в случае возврата null из любого мы получили null в x". S>Ну давайте перепишем: S>
S>Type1 x = null;
S>var x1 = Method1();
S>if(x1 != null)
S>{
S> var x2 = x1.Method2();
S> if(x2 != null)
S> {
S> var x3 = x2.Method3();
S> if(x3 != null)
S> x = x3.Method4();
S> }
S>}
S>
S>Это что-то принципиально поменяет?
Опа, вместо просто инициализации переменной получили изменяемое состояние. В исходном “водопроводном” варианте изменяемого состояния не было!
Просто инициализация выглядит так:
Type1 x;
var x1 = Method1();
if (x1 == null)
x = null;
else
{
var x2 = x1.Method2();
if (x2 == null)
x = null;
else
{
var x3 = x2.Method3();
if (x3 == null)
x = null;
else
x = x3.Method4();
}
}
Далее: Надо ли показывать к каким косякам может привести изменяемое состояние в данном случае?
В каком варианте будем подсчитывать многословность (количество слов)?
Вариант c OptionalValue:
var x = Method1()
.ProcessValue(_ => _.Method2())
.ProcessValue(_ => _.Method3())
.ProcessValue(_ => _.Method4());
При подсчете количества слов у меня получилось, что вариант c OptionalValue побеждает любой из трех вариантов с if-ами. Детали подсчета оформлю в виде текста и запощу, если это потребуется.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
S>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
Смысл -- сделать безопасным базовый/основополагающий прием трансформации кода Extract Method. Т.е. избежать катастрофы при использовании Extract Method, которая описана в первом посте.