Здравствуйте, IT, Вы писали:
IT>Я такой ПМ изобрёл у себя в Linq провайдере года два назад.
Я примерно тогда же.
IT>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно.
Но я еще не понял, что это говно . На что будешь его заменять? во что рефакторить?
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно. AP>Но я еще не понял, что это говно .
Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме.
AP>На что будешь его заменять? во что рефакторить?
Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue.
Он полностью изоморфен паре Value\HasValue
AP>К тому же, выяснилось, что в нашем частном случае pattern-matching совпал с методом Process http://rsdn.ru/forum/design/3955158.1.aspx
Ну на самом деле не совпал, так как реализация Process может быть любая (сайд-эффекты и прочие гадости). А вот мой Process (надо переименовать в Match) и Option с двумя (строго) альтернативами как раз и является PM.
private static Option<IFollowingPublicationCalculator> GetByOtherNumber(string catalogNumber)
{
return from number in сatalogNumber.ToOption()
where number != string.Empty
from pub in FindPreviousPublicationIdByOtherNumber(number)
select new OtherNumberFollowingPublicationCalculator(pub, number)
as IFollowingPublicationCalculator;
}
private static Option<IFollowingPublicationCalculator> GetBySelfNumber(string catalogNumber, int releaseMark)
{
return from number in catalogNumber.ToOption()
where number != string.Empty
from pub in FindPreviousPublicationIdBySelfNumber(number, releaseMark)
select new SelfNumberFollowingPublicationCalculator(pub, number)
as IFollowingPublicationCalculator;
}
private static Optional<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
string catalogNumber, string precededCatalogNumber, int releaseMark)
{
var calc = GetByOtherNumber(precededCatalogNumber);
return calc.HasValue ? calc : GetBySelfNumber(catalogNumber, releaseMark);
}
Первые два метода вернут None если
1)catalogNumber равен null или пуст
2)метод Find возвращает null
3)Приведение типа не сработает
Если цель как раз описать вычисления, не думая о том что где-то может внезапно вернуться null, этот код полностью покрывает сценарии.
Re[15]: Optional Value. Уменьшение количества null reference
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>Это ковариантность не нужна, ты до сих пор пример привести не смог даже. AP>Уже привел
. Ковариантность нужна .
Не-а. см выше.
G>>>>Любая реализация Option должна быть изоморфна любой другой. AP>>>Хватит уже пытаться подсунуть требования, которых нет! И которые не нужны. G>>... согласованность получения значение option и проверки наличия значения очень даже нужны. Просто потому что они в других библиотеках так сделаны. AP>Поведение моих реализаций согласовано с аналогичными реализациями в других библиотеках. Ты дописываешь свою реализацию, которую делаешь несогласованной с другими библиотеками. Почему претензии к результатам работы моего кода? Мой код делает ровно то, что заявлено, не больше, не меньше.
Претензии именно потому что я могу дописать такую реализацию.
G>>>>Любая реализация Option должна быть изоморфна любой другой. Иначе нарушаешь принцип наименьшего удивления. AP>>>Если я сделаю реализацию IComparer, который будет говорить что 3 больше 2. Отсортирую им массив. Как тут насчет принципа наименьшего удивления? G>>Не то сравниваешь. Тут вопрос согласованности, вот если ты сделаешь класс у которого не выполняется a.Equals(b) => a.GetHashCode() == b.GetHashCode(), то удивление будет ого-го, особенно при использовании в контейнерах. AP>Неплохая аналогия, да, тут надо делать согласованную реализацию двух методов. Аналогичные проблемы я отмечал для варианта, когда в интерфейсе IOptionalValue два свойства Value и HasValue. В моем коде у IOptionalValue метод один, поэтому согласовывать нечего.
не, у тебя метод Process обязан вызвать или один делегат или другой ровно один раз (там могут быть сайд-эффекты). Это гораздо более сильно условие чем согласованность двух методов.
Все было бы отлично, если бы не было возможности дописывать свои методы, но их дописывать можно. А вариант с Just\Some и None ничего дописывать не позволяет и контракт там не ломается.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>>>... Сегодня сделал бранч для рефакторинга, в том числе буду вычищать и это овно. AP>>Но я еще не понял, что это говно . IT>Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме.
У меня ровно обратный опыт. При свободном владении этими приемами достаточно запутанные (в том числе рекурсивные) алгоритмы надежно реализуются.
Однажды эти приемы кодирования помогли вывести сам алгоритм бизнес логики.
AP>>На что будешь его заменять? во что рефакторить? IT>Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий
То есть хорошая замена еще даже не придумана, а реализованный, работающий live вариант назвали говном. Как-то не по-девелоперски это.
Сейчас уже поздно, и честно говоря, я бегло посмотрел твой код, и нифига не понял сакрального смысла, заложенного в нем. Возможно, смысл есть, завтра посмотрю повнимательнее. А пока тупой вопрос.
G>... Рефакторим так: ...
Зачем производим рефакторинг?
Re[9]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
IT>>Попробуй его в каком-нибудь навороченном высокорекурсивном алгоритме. AP>У меня ровно обратный опыт. При свободном владении этими приемами достаточно запутанные (в том числе рекурсивные) алгоритмы надежно реализуются.
У меня опыт ровно обоюдный. Есть вещи, которые таким способом реализуются не плохо, есть, которые, от применения такого паттерна сильно страдают. Как правило пока речь идёт о компактных задачах, всё нормально. В алгоритмах на несколько тысяч строк вреда становится существенно больше, чем пользы.
AP>Однажды эти приемы кодирования помогли вывести сам алгоритм бизнес логики.
Это без проблем. ФП вообще рулит, если его правильно дозировать.
AP>>>На что будешь его заменять? во что рефакторить? IT>>Пока не знаю. По ходу что-нибудь придумаем. Главное по-меньше лямбд и замыканий AP>То есть хорошая замена еще даже не придумана, а реализованный, работающий live вариант назвали говном. Как-то не по-девелоперски это.
Замена давно придума, качетсвенная и на порядки более мощная — ПМ. Непонятно, почему Хейльсберг и ко так сильно ей противится.
А эмуляция МП на лямбдах — да, извини, но это самое обыкновенное унылое овно. Поначалу немного вставляет, но быстро проходит.
Если нам не помогут, то мы тоже никого не пощадим.
Re[4]: Optional Value. Уменьшение количества null reference-
Здравствуйте, IT, Вы писали:
IT>Или в Немерле. Но без ПМ этим пользоваться не очень удобно.
Функциональные программисты обычно делают Option/Maybe монадой и пользуются им соответственно, использовать его в паттерн-матчинге — вырожденный случай (который неплохо заменяется тренарным оператором и парой эксракторов, типа GetOrElse). http://en.wikipedia.org/wiki/Monad_(functional_programming)#Maybe_monad
//! Далее везде readNum возвращает Option-type
// Haskelldo
x <- readNum
y <- readNum
return $ x + y
// Scalafor {
x <- readNum()
y <- readNum()
} yield (x+y)
Так что надо определить для Option<T> Select, SelectMany, Where и пользоваться им из Linq:
from x in ReadNum()
from y in ReadNum()
select (x+y)
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Ага, я уже догадался, что вы напишете такое. И с некоторым запозданием я добавил комментарий:
AP>Extract Method становится безопасным при использовании техники кодирования, описанной в разделе “Катастрофа при Extract Method”. http://rsdn.ru/forum/design/3955011.1.aspx
Вы его заметили? Полное описание техники кодирования в первом посте. Если в вкратце, то это: не использование “return null(схематичное обозначение)” + OptionalValue.
Я заметил. Но я наверное тупой — я вижу утверждение, но не вижу никаких его доказательств. В начале вы утверждаете, что в вашем подходе "компилируется — значит работает". Покажите мне, как спровоцировать ошибку компиляции при попытке вернуть null там, где нельзя.
AP>В абзаце выше уже написал, что OptionalValue в сочетании c не использованием “return null(схематичное обозначение)”.
Ах, с неиспользованием... Имхо, это изоморфно байке про порошок от вшей, который надо было каждой вши в глаза втирать. Если я не использую null, то безо всяких OptionalValue я получаю безопасный код.
AP>OptionalValue нацелен не напрямую на это. Его прямая цель -- реализация optional логики. Да, наверное, в заголовок лучше вынести последнее. Сейчас не самый удачный заголовок.
По-моему, проблема — не в заголовке. У вас и описание задачи совершенно никак не связано с предлагаемым решением.
Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null. Оборудование всех мест, где нам нужен non-null, такими Mandatory<T> позволит нам гарантировать, что мы отловим момент записи null, а не чтения. Это, конечно, не так клёво, как ошибка компиляции, зато работает одинаково хорошо и для inline констант и для результатов вызовов.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Sinclair, Вы писали:
AP>>В абзаце выше уже написал, что OptionalValue в сочетании c не использованием “return null(схематичное обозначение)”. S>Ах, с неиспользованием... Имхо, это изоморфно байке про порошок от вшей, который надо было каждой вши в глаза втирать.
Ага, а еще многие просто моются регулярно. А этот способ не дает 100% гарантии, вши все равно могут появиться.
AP>>... Его прямая цель -- реализация optional логики. ... S>Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null.
Я про реализацию optional логики, выше выделил жирным. Причем тут присвоение null-ов?
AP>>OptionalValue нацелен не напрямую на это. Его прямая цель -- реализация optional логики. Да, наверное, в заголовок лучше вынести последнее. Сейчас не самый удачный заголовок. S>По-моему, проблема — не в заголовке. У вас и описание задачи совершенно никак не связано с предлагаемым решением. S>Прямое решение проблемы, о которой вы говорите — строго противоположно. Это Mandatory<T>, который сразу падает при присваивании null. Оборудование всех мест, где нам нужен non-null, такими Mandatory<T> позволит нам гарантировать, что мы отловим момент записи null, а не чтения. Это, конечно, не так клёво, как ошибка компиляции, зато работает одинаково хорошо и для inline констант и для результатов вызовов.
Что ваш Mandatory<T> предлагает для реализации optional логики? Передачу null-ов и “водопроводный” код, разобранный выше?
P.S. Кстати, OptionalValue можно сделать value типом. Но тогда, опять таки, теряем ковариантность. Надо подумать над этим выбором...
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>Он полностью изоморфен паре Value\HasValue
В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить?
G>private static Option<IFollowingPublicationCalculator> GetByOtherNumber(string catalogNumber)
G>{
G> return from number in сatalogNumber.ToOption()
G> where number != string.Empty
G> from pub in FindPreviousPublicationIdByOtherNumber(number)
G> select new OtherNumberFollowingPublicationCalculator(pub, number)
G> as IFollowingPublicationCalculator;
G>}
G>private static Option<IFollowingPublicationCalculator> GetBySelfNumber(string catalogNumber, int releaseMark)
G>{
G> return from number in catalogNumber.ToOption()
G> where number != string.Empty
G> from pub in FindPreviousPublicationIdBySelfNumber(number, releaseMark)
G> select new SelfNumberFollowingPublicationCalculator(pub, number)
G> as IFollowingPublicationCalculator;
G>}
G>private static Optional<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
G> string catalogNumber, string precededCatalogNumber, int releaseMark)
G>{
G> var calc = GetByOtherNumber(precededCatalogNumber);
G> return calc.HasValue ? calc : GetBySelfNumber(catalogNumber, releaseMark);
G>}
G>
G>Первые два метода вернут None если G>1)catalogNumber равен null или пуст G>2)метод Find возвращает null G>3)Приведение типа не сработает G>Если цель как раз описать вычисления, не думая о том что где-то может внезапно вернуться null, этот код полностью покрывает сценарии.
Ты это серьезно?!! Ты реально такое проделаешь с “живым” кодом? У меня все больше и больше сомнений в том, что ты действительно программируешь.
Ты можешь ответить, нафига ты это всё проделал?
Ручная работа с типами, о которой говорилось выше, выглядит так :
private static IOptionalValue<IFollowingPublicationCalculator> GetFollowingPublicationCalculator(
string catalogNumber, string precededCatalogNumber, int releaseMark)
{
if (string.IsNullOrEmpty(precededCatalogNumber))
{
return FindPreviousPublicationIdBySelfNumber(catalogNumber, releaseMark)
.ProcessValue<IFollowingPublicationCalculator>(value => new SelfNumberFollowingPublicationCalculator(value, catalogNumber));
}
else
{
return FindPreviousPublicationIdByOtherNumber(precededCatalogNumber)
.ProcessValue<IFollowingPublicationCalculator>(value => new OtherNumberFollowingPublicationCalculator(value, precededCatalogNumber));
}
}
Re[5]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
ANS>>Один или много объектов — это особенности реализации. См. Smalltalk, Objective-C. AP>А вот и нет. AP>Читаем статью по ссылке: AP>
AP>"[Одним из] недостатков является то, что паттерн 'Null Object' ... приводит к взрывному росту числа классов. Потому что необходимо создать свой 'пустой' класс для каждого абстрактного класса."
Имхо, это просто обобщение, которое возможно в силу более мощной платформы
AP>Я не знаком с Smalltalk и Objective-C, поэтому мне сложно оценить схожесть описанного в статье решения с OptionalValue. Но там идет речь о каком-то: AP>
AP>"Поедающий" сообщения nil
AP>OptionalValue ничего не поедает, поэтому, возможно, статья о другом.
Да, похоже то что ты предлагаешь никакого отношения `[Generalized ] Null Object` не имеет. Ты предлагаешь просто хак, который из null-не-объекта сделает null-объект. Дабы реализовать аналог управляющей конструкции ifNil:ifNotNil. Я уже писал, что это затея малополезная ввиду отсутствия нелокального возврата
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>Он полностью изоморфен паре Value\HasValue AP>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить?
Ты смысл слова "изоморфный" понимаешь?
Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными.
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Ты можешь ответить, нафига ты это всё проделал?
Чтобы показать что ни разу не нужен ни Proces, ни ковариантность. Причем покрывается гораздо более сложный случай частичных вычислений, чем в твоем коде.
ЗЫ. Ты так и не привел пример с получением данных из двух вебсервисов и отправкой третьему.
Re[7]: Optional Value. Уменьшение количества null reference-
Здравствуйте, gandjustas, Вы писали:
G>>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>>Он полностью изоморфен паре Value\HasValue AP>>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить? G>Ты смысл слова "изоморфный" понимаешь? G>Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными.
Да. В нашем случае такого преобразования нет.
Re[8]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Alexander Polyakov, Вы писали:
AP>Здравствуйте, gandjustas, Вы писали:
G>>>>>>Ну это неверно. Maybe монада и была придумана, как средство описать частичные вычисления, которые могут не возвращать результат в некоторых случаях. Правда имеет смысл как можно дольше оставаться в этой самой монаде, а метод Process такой способностью не обладает. AP>>>>>В том то и дело, что для практических целей помимо самой монады важно то, как осуществляется выход из этой монады. Метод Process как раз и является безопасным выходом из монады в отличие от небезопасного GetValue. G>>>>Он полностью изоморфен паре Value\HasValue AP>>>В нем нет “throw new Exception()”. В методе GetValue есть. О какой изоморфности тут можно говорить? G>>Ты смысл слова "изоморфный" понимаешь? G>>Это наличие биективного преобразования. Изоморфные множества (категории) можно считать в некотором роде эквивалентными. AP>Да. В нашем случае такого преобразования нет.
То есть ты хочешь сказать что из одного Process нельзя сделать пару Value\HasValue, а из этой пары нельзя сделать Process?
Вообще-то код доказывает обратное.
Но вот с твои IOptionalValue можно подсунуть реализацию, которая эту самую биективность нарушает и это очень плохо, потому что любой пользователь будет изначально рассчитывать именно на биективность.
Re[6]: Optional Value. Уменьшение количества null reference-
Здравствуйте, Andrei N.Sobchuck, Вы писали:
ANS>Да, похоже то что ты предлагаешь никакого отношения `[Generalized ] Null Object` не имеет. Ты предлагаешь просто хак, который из null-не-объекта сделает null-объект. Дабы реализовать аналог управляющей конструкции ifNil:ifNotNil. Я уже писал, что это затея малополезная ввиду отсутствия нелокального возврата
.
Да, фича прикольная. И была бы полезна для анонимных делегатов. Но поскольку в хорошем коде даже в обычных методах “return” в середине метода не очень часто встречается, поэтому потребность в нелокальном возврате довольно низкая.
И уж тем более отсутствие этой фичи не сильно влияет на полезность OptionalValue.