Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, Alexander Polyakov, Вы писали:
AP>>Отсюда вывод: не использовать null в качестве возвращаемого значения! То есть набирать на клавиатуре null только: AP>>Но наша цель более скромная – уменьшить количество null-ов. Кстати, по пунктам a и b еще можно кое-что отвоевать. S>Не очень понятен смысл неиспользования null-ов. Проблема, я так понимаю, в том, что NRE упадёт слишком поздно?
Проблема в том что NRE вообще упадет.
Рассмотрим код:
var x = Method1().Method2().Method3().Method4();
Если везде возвращаются ref-типы, то каждый из методов может вернуть null.
Можно использовать контракты чтобы доказать что null не вернется.
Но иногда все таки методы возвращают null и это является нормальным поведением, а нас во всей операции интересует только конечный результат, тогда хорошо бы иметь способ описать частичные вычисления (которые могут не вернуть результата). В других языках есть конструкции типа .?, которые возвращают null если выражение слева null, но далеко не всегда есть возможность возвращать null, например если результат — value-type.
Вот и реализуют абстракции типа Option, которые позволяют избежать использования null и водопроводного кода типа:
var x1 = Method1();
if(x1 == null) return null;
var x2 = x1.Method2();
if(x2 == null) return null;
var x3 = x2.Method3();
if(x3 == null) return null;
return x3.Method4();
Но у обоих реализаций, представленных здесь, есть недостаток (Elevate им тоже обладает). Вполне можно написать так:
Здравствуйте, Qbit86, Вы писали:
AP>>Метод Select по правилам должен называться SelectMany. Q>По некоторым другим правилам должен называться и вовсе Bind, евпочя
Конечно это мелочи, но все же сделаю замечание. Мы в рамках C#-а. А здесь правила именования уже выбрали до нас. Монадический метод Bind назвали SelectMany. В частности, на второй перегруженный метод SelectMany завязан query comprehension syntax. Первый SelectMany в query comprehension syntax не участвует, но заменять пару перегруженных методов парой разноименных не очень удобно.
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
S>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод.
Метод с условным оператором внутри заметно лучше полиморфного метода?
S>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
).
Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно.
AP>>Мои аргументы в пользу варианта из первого поста: AP>> AP>>... AP>>В случае если не срабатывает type inference, то для extension метода Process придется явно прописывать значения обоих generic параметров. А если Process является методом интерфейса, то прописывать придется значение только одного generic параметра. AP>>S>2. Можно пример?
var result = optionalValue.Process<IA>(value => new B(), () => new C()); //если метод интерфейсаvar result = optionalValue.Process<SomeClass, IA>(value => new B(), () => new C()); //если extension методinterface IA {}
class B: IA { }
class C: IA { }
Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример. Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто:
А попробуйте написать реализацию интерфейса с двумя методами :
public interface IOptionalValue<TValue>
{
TValue Value { get; }
bool HasValue { get; }
}
S>З.Ы. В некоторых случаях может оказаться удобнее OptionalValue, построенный не на АТД, а на кортеже флага и значения. Такая штука шикарно передается в качестве параметров по умолчанию. Описано у desco.
Спасибо, почитаю.
Re[6]: Optional Value. Уменьшение количества null reference-
AP>Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример. Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто: AP>
А как будет выглядеть композиция таких методов?
Например надо получить от двух сервисов данные, как-то обработать их и отправить третьему.
AP>А попробуйте написать реализацию интерфейса с двумя методами :
А в чем сложность?
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>Метод с условным оператором внутри заметно лучше полиморфного метода?
Да, т.к. расширять иерархию нет надобности.
S>>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
). AP>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно.
Разве оператор is пока недоступен?
S>>2. Можно пример? AP>
AP>var result = optionalValue.Process<IA>(value => new B(), () => new C()); //если метод интерфейса
AP>var result = optionalValue.Process<SomeClass, IA>(value => new B(), () => new C()); //если extension метод
AP>interface IA {}
AP>class B: IA { }
AP>class C: IA { }
AP>
решается через Process(value => (IA) new B(), () => (IA) new C());
AP>Кстати, 3-ий аргумент. Реализации свойств Value и HasValue в обязательном порядке должны быть согласованы: если HasValue возвращает true, то Value не должно кидать исключение. Для демонстрации этой проблемы приведу пример.
Я как раз и не настаиваю на наличии Value и HasValue.
AP>Отмечу, что пример искусственный, эта же задача решается с помощью двух существующих реализаций IOptionalValue. Но все же. Никто не мешает добавить свою имплементацию интерфейса IOptionalValue, которая будет лезть на web service и брать оттуда значение. Если у интерфейса IOptionalValue всего один метод Process, то все прямолинейно и просто:
AP>А попробуйте написать реализацию интерфейса с двумя методами :
Здесь я как раз предпочитаю чистый АТД, в том виде, в котором его например моделирует F#. Лишние реализации исключены.
Re[2]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinix, Вы писали:
AP>>Хочется иметь такую технику кодирования, чтобы Extract Method не переводил ошибки компиляции в ошибки run time-а. S>Правильное решение этой проблемы — использование контрактов и статической верификации. Если бы оно ешё работало...
Называть неработающее решение правильным как-то странно .
S>... использование контрактов и статической верификации. ...
Ага, можно использовать, а можно не использовать. То есть это является дополнением. И следовательно, это менее практично. С OptionValue ситуация другая, оно предлагает замену null-ам, а не дополнение. Почувствуйте разницу .
S>Да. Но, вместо того, чтобы решать проблему в её источнике — методе ...
Источник проблемы всегда в методе? Странное утверждение. Из него следует, что optional логика имеет право имплементироваться только внутри одного метода. Это бред.
AP>> оба варианта ведут себя одинаково -- если код компилируется, то он работает. S>Да. Но, вместо того, чтобы решать проблему в её источнике — методе, вы передаёте ответственность по соблюдению контракта всему остальному коду. NullReferenceException хотя бы гарантировал, что при ошибке в вашем коде программа упадёт. OptionalValue маскирует исходную проблему и источник её возникновения: "ой, у нас тут значения нет — фиг с ним, подсунем что-нить"
Странная у тебя логика, указания статического верификатора контрактов ты уважаешь, а на сообщения старого доброго компилятора реагируешь как “фиг с ним, подсунем что-нить”.
Re[3]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех .
Здравствуйте, gandjustas, Вы писали:
G>Приведи пример где ковариантность необходима. G>... G>Приведи пример где ковариантность необходима.
Ты вообще программируешь? Очень странно слышать такой вопрос от практикующего программиста.
Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>.
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Приведи пример где ковариантность необходима. G>>... G>>Приведи пример где ковариантность необходима. AP>Ты вообще программируешь? Очень странно слышать такой вопрос от практикующего программиста.
Вообще да.
AP>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>.
Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
AP>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось.
В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
AP>>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось. AP>В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали.
То есть не так часто встречались чтобы это было значительным преимуществом для Option.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
S>>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>>Метод с условным оператором внутри заметно лучше полиморфного метода? S>Да, т.к. расширять иерархию нет надобности.
Не вижу как этот аргумент позволяет выделить “лучшего” в исходном утверждении. Оно показывает лишь то, что условный оператор может оказаться не хуже.
S>>>1. Не нужны эти свойства, если пойти через тест типа аки в ПМ (здесь
). AP>>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно. S>Разве оператор is пока недоступен?
Если это обычный C#-вский оператор “is”, то твоя идея сводится к реализации метода HasValue(). У тебя не будет HasValue в базовом интерфейсе, а будет extention метод HasValue(). Опять таки, не вижу существенной разницы между полиморфным свойством и extention методом. А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
AP>>>>Возьми любую задачу, где есть полиморфизм, например, пусть имеются типы TBase, TSubtype1 и TSubtype2. Добавь в эту задачу optional логику. Переменные исходных типов заменятся на IOptionalValue<TBase>, IOptionalValue<TSubtype1> и IOptionalValue<TSubtype2>. Если нет ковариантности, то метод с параметром IOptionalValue<TBase> не сможет принять объект типа IOptionalValue<TSubtype1>. G>>>Вот меня и интересует конкретный практический пример где такое нужно, а то в моей практике не встречалось. AP>>В моей встречались. Сейчас мне влом поднимать контекст конкретных задач, и вспоминать детали. G>То есть не так часто встречались чтобы это было значительным преимуществом для Option.
Вывод не верный. Экзамен по элементарной логике не сдан, приходите в следующий раз .
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
S>>>>Ближе собственно тем, что при работе с АТД используется один неполиморфный метод. AP>>>Метод с условным оператором внутри заметно лучше полиморфного метода? S>>Да, т.к. расширять иерархию нет надобности. AP>Не вижу как этот аргумент позволяет выделить “лучшего” в исходном утверждении. Оно показывает лишь то, что условный оператор может оказаться не хуже.
на мой вкус — лучше в конкретном случае. Навязывать и убеждать не собираюсь.
AP>>>Да, тест типа выглядит симпатичнее свойства HasValue (по крайней мере, на первый взгляд). Но, к сожалению, в C# это пока недоступно. S>>Разве оператор is пока недоступен? AP>Если это обычный C#-вский оператор “is”, то твоя идея сводится к реализации метода HasValue().
Сводится. Только зачем ее сводить?
AP>У тебя не будет HasValue в базовом интерфейсе, а будет extention метод HasValue().
Для чего он нужен?
AP>Опять таки, не вижу существенной разницы между полиморфным свойством и extention методом.
Полиморфное свойство не нужно.
AP>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея.
Другие реализации не нужны. Но запретить тебе их желать я не могу.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>Это замечание незначительно само по себе, G>Да ну? Сломать контракт это фигня?
Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего!
G>>>Но я могу сколько угодно своих реализаций подсовывать.
Пожалуйста подсовывай, мой код будет корректно работать.
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, samius, Вы писали:
AP>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>Другие реализации не нужны. Но запретить тебе их желать я не могу.
Мне они тоже не нужны. Мое желание -- иметь ковариантность.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Andrei N.Sobchuck, Вы писали:
AP>>Скорее нет, чем да. Если пользоваться описаниями ссылка1, ссылка2, то Null Object Pattern предлагает делать кастомный интерфейс и кастомную реализацию Null Object-а для каждого случая. A OptionalValue один для всех . ANS>Один или много объектов — это особенности реализации. См. Smalltalk, Objective-C.
А вот и нет.
Читаем статью по ссылке:
"[Одним из] недостатков является то, что паттерн 'Null Object' ... приводит к взрывному росту числа классов. Потому что необходимо создать свой 'пустой' класс для каждого абстрактного класса."
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>Это замечание незначительно само по себе, G>>Да ну? Сломать контракт это фигня? AP>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего!
G>>>>Но я могу сколько угодно своих реализаций подсовывать. AP>Пожалуйста подсовывай, мой код будет корректно работать.
Твой — будет, а все вместе — нет.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>Проблема этого интерфейса что он не энфорсит контракт, это при том что кроме Some\Just и None реализаций не нужно. Но я могу сколько угодно своих реализаций подсовывать. AP>>>>Это замечание незначительно само по себе, G>>>Да ну? Сломать контракт это фигня? AP>>Какой контракт? Ты вообще о чем? Нет у меня никакого контракта. Ломать нечего! G>
Что тебя так рассмешило?
G>... а все вместе — нет.
Код в студию.
Re[10]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, samius, Вы писали:
AP>>>А поскольку из-за желания ковариантности мы не может запретить создание других реализаций, то завязка на типы классов не очень хорошая идея. S>>Другие реализации не нужны. Но запретить тебе их желать я не могу. AP>Мне они тоже не нужны. Мое желание -- иметь ковариантность.
Ну ты же начал доказывать что ковариантность всем ой как нужна. А на деле не нужна.
Я собственно и до .NET4 не испытывал проблем из-за отсутствия ковариантности интерфейсов, где надо проделывал приведение типа ручками.
Для делегатов вариантность гораздо более существенна.