Сообщение Re[59]: Haskell нужен! (в Standard Chartered Bank) от 26.02.2015 14:43
Изменено 26.02.2015 14:44 Evgeny.Panasyuk
J>>да нету никакого кода в load_order, самый обычный код, возвращающий самый обычный order безо всяких свойств.
J>>Все интересное начинается потом, когда ты собираешься что-то с ордером делать — а функции, которые ты собираешься звать, требуют те или иные установленные свойства.
S>И, простите, чем это отличается от нашего нынешнего кода, где изо всех типов есть только самый обычный ордер, безо всяких "свойств"?
Тем что теперь компилятор будет заставлять пользователя проверять свойства, и соответственно он не сможет проигнорировать тот факт, что тут две логические ветки (свойство верно или неверно).
S>Непонятно, в чём бенефит статической типизации. Я могу описать функцию increase_amount вот так:
S>
S>public void Order increase_amount(Order order, Money newAmount)
S>{
S> Contracts.Assert(order, (o)=> !o.HasRisk); // выбросим исключение!
S> Contracts.Assert(order, (o)=> !o.Shipped); // выбросим исключение!
S> Contracts.Assert(order, (o)=> newAmount <= 1.20 * o.CurrentAmount) // выбросим исключение!
S> return order.Clone().SetAmount(newAmount);
S>}
S>Что проверяют твои Assert'ы — нарушение предусловия или вполне легальный вариант данных? Это важно.
Обычно assert означает нарушение предусловия, и лучшей реакцией будет склейка ласт ASAP — так как программа попала в неизвестное состояние, непонятно каким способом.
EP>Нарушение предусловия это баг в программе, программа находится в том состоянии в котором не должна была по логике вещей, и как она туда попала неизвестно, лучше всего пристрелить такую программу как взбесившуюся собаку. Почитай наконец что такое precondition.
EP>Предусловия можно проверять, и как-то энфорсить, но отнюдь не обязательно. Например assert'ы энфорсящие предусловия часто используют только в отладочных режимах.
EP>Система типов позволяет энфорсить некоторые предусловия в compile-time, но не все. Я даже больше скажу, далеко не все предусловия можно проверить в runtime — попытка такой проверки попросту может поломать инварианты, и сделать невозможным достижение постусловий.
S>Вся разница — в том, что теперь в try_increase_amount мне придётся провести корректное приведение типов:
S>
...
S> var o = checkNoRisk(order); // выбросим исключение, если есть риск, вернём Order<Risk.None, S> иначе
S> var o2 = checkNotShipped(o); // выбросим исключение, если зашиплен, вернём Order<Risk.None, Shipped.None> иначе
S>...Необязательно исключение, это могут быть две разные ветки.
S>Но мы наблюдаем те же яйца, вид сбоку. Всё, try_increase_amount — это наш верхний уровень, мы не можем ничего доказать за её пределами.
S>У нас совершенно нормально иметь workflow, в котором мы пытаемся увеличить amount у уже отправленного ордера. Потому что компилятор видит ровно один шаг этого workflow.
S>В итоге, мы написали кучу кода, напрягли компилятор, но никак не улучшили поведение системы. У нас уже и так increase_amount была вполне локальна — все бизнес-правила выписаны в начале, шансы напортачить в них минимальны. Ну вынесли мы требования к флагам из тела в сигнатуру — так ведь нам это никак не помогло!
Для задачи Mamut'а
Дата: 05.02.15
EP>Если же для запуска функции нет необходимости делать проверки, change_amount сама всё что нужно проверяет внутри, и более того её запуск с невыполненными условиями не является ошибкой, а вполне штатным режимом — то пытаться переписать все эти внутренние проверки на типы, не вижу смысла, это никак не отразится на местах вызова этой функции.
J>>да нету никакого кода в load_order, самый обычный код, возвращающий самый обычный order безо всяких свойств.
J>>Все интересное начинается потом, когда ты собираешься что-то с ордером делать — а функции, которые ты собираешься звать, требуют те или иные установленные свойства.
S>И, простите, чем это отличается от нашего нынешнего кода, где изо всех типов есть только самый обычный ордер, безо всяких "свойств"?
Тем что теперь компилятор будет заставлять пользователя проверять свойства. И соответственно он не сможет проигнорировать тот факт, что тут две логические ветки (свойство верно или неверно), и не сможет порушить предусловия вызываемой функции.
S>Непонятно, в чём бенефит статической типизации. Я могу описать функцию increase_amount вот так:
S>
S>public void Order increase_amount(Order order, Money newAmount)
S>{
S> Contracts.Assert(order, (o)=> !o.HasRisk); // выбросим исключение!
S> Contracts.Assert(order, (o)=> !o.Shipped); // выбросим исключение!
S> Contracts.Assert(order, (o)=> newAmount <= 1.20 * o.CurrentAmount) // выбросим исключение!
S> return order.Clone().SetAmount(newAmount);
S>}
S>Что проверяют твои Assert'ы — нарушение предусловия или вполне легальный вариант данных? Это важно.
Обычно assert означает нарушение предусловия, и лучшей реакцией будет склейка ласт ASAP — так как программа попала в неизвестное состояние, непонятно каким способом.
EP>Нарушение предусловия это баг в программе, программа находится в том состоянии в котором не должна была по логике вещей, и как она туда попала неизвестно, лучше всего пристрелить такую программу как взбесившуюся собаку. Почитай наконец что такое precondition.
EP>Предусловия можно проверять, и как-то энфорсить, но отнюдь не обязательно. Например assert'ы энфорсящие предусловия часто используют только в отладочных режимах.
EP>Система типов позволяет энфорсить некоторые предусловия в compile-time, но не все. Я даже больше скажу, далеко не все предусловия можно проверить в runtime — попытка такой проверки попросту может поломать инварианты, и сделать невозможным достижение постусловий.
S>Вся разница — в том, что теперь в try_increase_amount мне придётся провести корректное приведение типов:
S>
...
S> var o = checkNoRisk(order); // выбросим исключение, если есть риск, вернём Order<Risk.None, S> иначе
S> var o2 = checkNotShipped(o); // выбросим исключение, если зашиплен, вернём Order<Risk.None, Shipped.None> иначе
S>...Необязательно исключение, это могут быть две разные ветки.
S>Но мы наблюдаем те же яйца, вид сбоку. Всё, try_increase_amount — это наш верхний уровень, мы не можем ничего доказать за её пределами.
S>У нас совершенно нормально иметь workflow, в котором мы пытаемся увеличить amount у уже отправленного ордера. Потому что компилятор видит ровно один шаг этого workflow.
S>В итоге, мы написали кучу кода, напрягли компилятор, но никак не улучшили поведение системы. У нас уже и так increase_amount была вполне локальна — все бизнес-правила выписаны в начале, шансы напортачить в них минимальны. Ну вынесли мы требования к флагам из тела в сигнатуру — так ведь нам это никак не помогло!
Для задачи Mamut'а
Дата: 05.02.15
EP>Если же для запуска функции нет необходимости делать проверки, change_amount сама всё что нужно проверяет внутри, и более того её запуск с невыполненными условиями не является ошибкой, а вполне штатным режимом — то пытаться переписать все эти внутренние проверки на типы, не вижу смысла, это никак не отразится на местах вызова этой функции.