Re: Про типы и логику
От: nikov США http://www.linkedin.com/in/nikov
Дата: 05.02.15 16:53
Оценка: 43 (2) +13
Здравствуйте, Mamut, Вы писали:

M>Исходные данные:

M>- есть заказ
M>-- он может быть отправлен или неотправлен
M>-- он может быть предоплачен или не предоплачен
M>-- он может быть помечен, как несущий риск или не помечен

Высокоуровневую логику на типах писать сложно и обычно нерентабельно, и это обычно никто не делает. Но вот пример ошибки в твоей задаче, с которой типы могут помочь: представь, что все три флага выше имеют просто тип boolean. Программист может случайно ошибиться, например, в порядке аргументов, и вместо того, чтобы пометить заказ как "предоплачен", пометить его как "отправлен". Если же вместо boolean мы будем использовать три разных типа, с двумя значениями каждый, такую ошибку будет очень трудно совершить случайно. Точно так же, можно использовать разные типы для количества и цены товара, и т.д. Компилятор может проверять, что мы случайно не складываем погонные метры с килограммами, или что мы не ищем значение в килограммах внутри списка, элементы которого являются "количеством ящиков".
Отредактировано 05.02.2015 16:58 nikov . Предыдущая версия .
Про типы и логику
От: Mamut Швеция http://dmitriid.com
Дата: 05.02.15 15:40
Оценка: 37 (4) -1
Выношу из соседнего обсуждения
Автор: Mamut
Дата: 02.02.15
, так как там много флейма и отсутсвие конструктива.

Мне просто действительно интересно. Многие утверждают, что типы помогают (чуть ли не) во всем, вплоть до того, что «тайпчекер проверяет именно логику».

У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить. Самое главное, если вся логика упаковывается в типы, каким образом проверяется правильность реализации этой логики на типах? Свое решение «в лоб» я тоже напишу, естественно Языки программирования — любые Но желательно приближенные к реальному миру (то есть те, что хоть в какой-то мере используются в природе).

Исходные данные:
— есть заказ
-- он может быть отправлен или неотправлен
-- он может быть предоплачен или не предоплачен
-- он может быть помечен, как несущий риск или не помечен

Что с заказом можно сделать:

— Можно изменить сумму заказа: увеличить или уменьшить (в реальности это конечно сложнее, так как изменяется не сумма, а товары в заказе: они могут добавляться, изменяться, добавляться скидки и штрафы и многое другое. И сумма заказа — это сумма товаров. Но для простоты возьмем именно этот случай).


Собственно задача. Мы будем эмулировать реальную разработку, в которой требования меняются. Мне интересно, как будет меняться реализация с типами по мере изменения требований. Все крутится вокруг изменения суммы. Для спортивности: не смотрите в следующий шаг, пока не реализован первый шаг.

Шаг 1.

  • если заказ неотправлен и непредоплачен, можно увеличивать и уменьшать
  • если заказ отправлен, нельзя увеличивать, можно уменьшать
  • если сумма увеличивается, мы должны провести risk check. если risk check не проходит, товар никак не помечается, но изменение суммы не проходит
  • если товар помечен, как risk, то изменять сумму нельзя

    Шаг 2.

    Изменение суммы:

    Все то же самое, что и в шаге первом, только:

  • увеличивать можно на max(фиксированная сумма1, процент1 от оригинальной суммы заказа)
  • уменьшать можно на max(фиксированная сумма2, процент2 от оригинальной суммы заказа),
    где сумма1, сумма2, процент1, процент2 — это конфигурация, считываемая из базы данных

    Если изменение не попадает в эти рамки, то увеличить/уменьшить нельзя


    Шаг 3.

    Все то же самое, что и в шаге 2. Дополнительно:

  • если заказ предоплачен (неважно, отправлен или нет), можно увеличивать сумму, если это разрешено конфигурацией магазина. Сумма, на которую можно увеличивать высчитывается, как в шаге 2
  • если заказ предоплачен, неотправлен, и сумма увеличивается, надо сделать auth-запрос в банк. если он не срабатывает, увеличить нельзя.
  • если заказ предоплачен, отправлен, и сумма увеличивается, надо сделать auth-запрос в банк на разницу в сумме, а потом сделать capture запрос на всю сумму. Если хоть один из них не срабатывает, увеличить нельзя.


  • dmitriid.comGitHubLinkedIn
    Re: Про типы и логику
    От: IT Россия linq2db.com
    Дата: 06.02.15 04:40
    Оценка: 6 (1) +4
    Здравствуйте, Mamut, Вы писали:

    M>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить.


    Простейшая задача, выковырянная неизвестно из какого места, да ещё и адаптированная под точку зрения автора, ничего не доказывает.

    Если ты когда-нибудь собирал мозаичные пазлы, то должен был заметить, что различная форма фрагментов рисунка позволяет избежать большинства ошибок и резко ускорить выполнение задачи. Типы в любой логике выполняют примерно туже самую роль.
    Если нам не помогут, то мы тоже никого не пощадим.
    Re[3]: Про типы и логику
    От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
    Дата: 06.02.15 07:35
    Оценка: 38 (1) +3
    Здравствуйте, Mamut, Вы писали:

    M>Например?


    У нас есть функция и типы данных:
    struct bar{ void f1(){}; void f2(){};}
    struct zoo{void f1(){};}
    
    void foo(bar data);

    Если ты пишешь на языке не поддерживющем проверку типов на этапе сборки, ты должен написать тест который докажет что foo() не поплохеет если в нее по ошибке будет скормлен объект типа zoo. Проверка типа во время компиляции убережет тебя от, во-первых, написания теста, во-вторых от добавления лишней защитной логики в foo(). Мы же явно не хотим что бы foo() падала или как-то еще непортребно себя вела при получении неверного типа в качестве входных данных.
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 07:20
    Оценка: 5 (1) -2 :)
    M>>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить.
    IT>Простейшая задача, выковырянная неизвестно из какого места, да ещё и адаптированная под точку зрения автора, ничего не доказывает.

    1. Выковырянная из известного места
    2. Под мою точку зрения я ничего не подгонял — это то, с чем приходится работать.

    Если эта задача настолько проста, что же апологеты типов не могут ее решить, несмотря на стопятьсот красивых текстов о том, как типы все решают?

    IT>Если ты когда-нибудь собирал мозаичные пазлы, то должен был заметить, что различная форма фрагментов рисунка позволяет избежать большинства ошибок и резко ускорить выполнение задачи. Типы в любой логике выполняют примерно туже самую роль.


    Демагогия.

    Могу только повторить. Говоришь про любые концепции — вот тебе и горы примеров, и примеры кода и все, что угодно. Как только начинаются сказки про то, как типы спасут цивилизацию — все, сплошные сказки на множество страниц текста ни о чем и ровно ноль примеров кода. А те, что есть, являются примитивнейшими примерами, которые сыпятся при малейшей попытке их хоть как-то усложнить.

    Но зато при постоянных пафосных заявлениях про мозаику, тайпчекер проверит логику и прочая и прочая.

    http://rsdn.ru/forum/philosophy/5945470.1
    Автор: genre
    Дата: 05.02.15
    (на стопятидесятом сообщении в топике)

    Вот это все настолько красиво звучит, что было бы здорово увидеть пример, как запросто отразить это в определении типа.


    Ответ? Все будет зашиьись, верь мне
    Автор: jazzer
    Дата: 05.02.15
    .


    dmitriid.comGitHubLinkedIn
    Re[22]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 11.03.15 12:23
    Оценка: -1 :)))
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    EP>>>Ты действительно никогда не использовал итераторы?

    I>>А ты бросил пить ?

    EP>Ты чего пример partition_point удалил? Потому что области применения двоичного поиска очевидны, да?


    Я сколько ни видел реализаций такого поиска, всё время было в лоб, безо всяких итераторов и тд и тд. Пудозреваю, твои итераторы не такая классная мулька, как тебе кажется.

    I>>>>Попробуй придумать такой же пример,

    EP>>>Какой такой же? Что конкретно показывает твой пример "редактор векторной графики"?
    I>>Показывает, где и как будет применяться либа для векторных операций всяких. Там же, кстати, применяется и афинное пространство. Если хочешь, можешь попробовать на этом примере объяснить, за счет чего афинное пространство зарулит векторное.

    EP>Уже объяснял. Разжёвывать не собираюсь, ибо интересуешься ты не в познавательных целях, а чисто ради упражнения в демагогии/троллинге


    Примеров то как не было, так и нет. Я сдела твою работу — привел пример. И даже на нём тебе нечего сказать.

    Вобщем, суммируя тобой сказаное, получается примерно так: "Вот в реальном мире точно всё по другому !"
    Re[11]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 08.02.15 22:34
    Оценка: 24 (2) +1
    Здравствуйте, Mamut, Вы писали:

    EP>>Повторюсь в очередной раз, для этой задачи это не имеет смысла.

    M>Предложи задачу, для которой имеет

    Для тех задач где есть какие-то предусловия:
    template<typename State>
    enable_if_t
    <
        State::prepared && State::risk_checked || State::approved_by_boss
    > change_amount_unconditionally(Order<State> x, Money amount)
    {
        // ...
    }


    EP>>Да.

    EP>>Да, желательно.
    EP>>Всё верно.
    M>Но при этом «для этой задачи не имеет смысла»

    Да, и что из этого?

    M>Причем оно внезапно перестало иметь смысл ровно после того, как все те же множественные условия, о которых ты говорил, остались на месте, только стали не выдуманные тобой вызовы с *-условиями, а стал один вызов


    Состояние ранее являвшееся ошибкой, стало вполне штатным режимом работы, и это повлияло на возможные варианты реализации этого в коде. И что тебя удивляет?

    EP>>Вся эта полемика уже сводится к:

    M>Ложные аналогии такие ложные

    Я вижу это именно так. Если ты видишь это по-другому, можешь дополнить/исправить аналогию.

    M>>>Мне не нравится, что высокопафосные заявления про, например, "на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time." скатываются в банальное «ну, главное чтобы килограммы с метрами не складывались»

    EP>>Так действительно, при наличии compile-time аргументов их можно использовать в сложных условиях.
    M>Определи понятие «сложные условия» и почему условия в моей задачи, видимо, недостаточно сложные

    Так сразу же:

    EP>>Например если есть compile-time массив, его можно отсортировать, делать двоичный поиск, и на основании результата разрешать или запрещать вызов конкретной функции. С чем не согласен-то?

    M>1. Нафига?

    Пример сложных условий, с нетривиальными вычислениями.

    M>Или — о ужас — данные о заказе не compile-time, из-за этого ничего поделать нельзя? Ну извини, реальный мир он такой — подавляющее большинство данных получаются не в compile-time


    Runtime данные можно переводить в compile-time, причём данные любой сложности, об этом я неоднократно говорил в предыдущем топике, и даже приводил конкретный код. Вопрос упирается в code-bloat.
    Перевести несколько bool из runtime в compile-time — не проблема. А вот например перевод unsigned price — скорей всего будет непрактичным.

    EP>>Чем тебе не нравится пример с аффинным пространством? Конкретный пример std::chrono — time_point и duration.

    EP>>http://en.cppreference.com/w/cpp/chrono
    M>Вау. Не прошло и недели и стапятидесяти сообщений, как внезапно кто-то из апологетов родил хоть что-то похожее на реальный пример. Не знаю, при чем тут аффинные пространства,

    Это и есть пример аффинного пространства, где duration это вектор, а time_point — точка.

    M>из того, что вижу — это энфорсинг типов. Ну, то самое «не складывать килограммы с метрами».


    Более сложный пример: на типах можно задать грамматику DSL, и разрешать только те выражения, которые проходят проверку. Пример — Boost.Proto.

    M>Отлавливается первым же залетным тестом


    Mars Climate Orbiter тесты не спасли. Хотя, по всей видимости, тестировалось всё более пристрастно чем типичный опердень.


    M>Ну да, при рефакотринге будет приятно. В реальных задачах будет занимать мизерную часть проблем.


    Считай перед вызовом каждой функции расставляются виртуальные assert'ы, которые отрабатывают на этапе компиляции.
    В динамических же языках эти assert'ы подразумеваются, но никак не энфорсятся. И соответственно чем больше программа, тем больше вероятность что какая-то из ошибок подобного рода будет пропущена. Если вероятность пропуска/фейла одного такого assert'а 0.01, то уже для 230 мест вероятность пропуска хотя бы одного будет 0.9.
    И даже 100% покрытие строчек кода тестами не даёт гарантии что все ошибки этого класса найдены.
    Re[3]: Ах да, мое решение :)
    От: Evgeny.Panasyuk Россия  
    Дата: 06.02.15 21:08
    Оценка: 3 (1) +2
    Здравствуйте, artelk, Вы писали:

    A>В идеале хотелось бы, чтобы можно было "помечать" тип произвольной комбинацией аттрибутов и чтобы можно было сказать компилятору, что в функцию foo можно передавать только Order, помеченный аттрибутами A,B и C, а в функцию bar — помеченный C и D, так что если у нас есть Order, помеченный A, B, C и D, то его можно передать в обе функции и т.п. Не знаю, можно ли такой сделать на Хаскеле или C++. Зависимыми типами и прочими liquid types пахнет... )


    Основная проблема с проверкой условия "увеличивать можно на max(фиксированная сумма1, процент1 от оригинальной суммы заказа)" в compile-time. Для этого придётся переводить runtime price в compile-time price, соответственно разных воплощений типов-цен будет столько же, сколько и возможных вариантов цен (а соответственно будет много воплощений функции принимающих эти типы).
    Если же проверка цены допустима в runtime, и не нужно делать из неё ограничение-тип — то получается намного проще.

    Вообще, всё зависит от пред/пост-условий требуемой функции, и соответственно мест в которых она используется.
    Если в её предусловия входит выполнение всех этих ограничений/условий, то без предварительных проверок её запускать нельзя. И соответственно все эти проверки надо городить в месте каждого вызова (либо удостовериться в их выполнении другими способами) — то в этом случае форсирование этих условий системой типов имеет смысл.
    Если же для запуска функции нет необходимости делать проверки, change_amount сама всё что нужно проверяет внутри, и более того её запуск с невыполненными условиями не является ошибкой, а вполне штатным режимом — то пытаться переписать все эти внутренние проверки на типы, не вижу смысла, это никак не отразится на местах вызова этой функции.

    В предыдущей теме, в некоторых местах
    Автор: Mamut
    Дата: 03.02.15
    разговор шёл именно о предварительных проверках, а не внутренних:

    M>То есть четвертый пункт — это
    M>

    M>if is_activated(Order) and is_auth_only(Order):
    M>  do_capture(Order)
    M>

    M>Еще раз: как именно типы мне помогут?

    В таких случаях пытаться встроить контракт/предусловие в систему типов вполне имеет смысл
    Re[6]: Ах да, забыл
    От: jazzer Россия Skype: enerjazzer
    Дата: 07.02.15 03:18
    Оценка: +3
    Здравствуйте, Mamut, Вы писали:

    J>>Еще раз — типы вводятся не для легкости, а для корректности.

    J>>Единственное, что облегчают типы — это проверку корректности, потому что ею автоматически занимается компилятор, а не программер с лупой по коду ползает.
    J>>Про то, что их легче писать, никто не говорил (ну, я не говорил; за всех не скажу).

    M>

    M>Не очень понятно, что должно было продемонстрировать твое решение в лоб, кроме того, что задачу можно решить в лоб
    M>В этом никто и не сомневался, вообще-то.


    M>Да, никто не сомневался. Я написал это за 10 минут, на работе. Про типы мне прожужживают уши уже который день и которое сообщение подряд. Но только сказками и рассказами:


    M>Стопятьсот сообщений о том, как с типами все зашибись.


    И стопятьсот сообщений от тебя про белого бычка, тупо игнорирующих все, что тебе говорят (и это сообщение — тоже яркий тому пример: ты тупо проигнорировал мои слова наверху, и так почти со всем).
    И потом тебе еще хватает уж не знаю чего заявлять "там много флейма и отсутсвие конструктива".
    В зеркало посмотрись сначала.
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[9]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 07.02.15 10:16
    Оценка: +3
    Здравствуйте, Mamut, Вы писали:

    EP>>order<processed, prepaid, not_risk, amount_rise_allowed>, либо просто order<state>

    M>Можно увидеть это на примере решения задачи, которую я привел? Ну, на основе твоих заявлений:

    Повторюсь в очередной раз, для этой задачи это не имеет смысла.

    M>- на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time.


    Да.

    M>- как можно больше логики кодировать в типах и проверять компилятором.


    Да, желательно.

    M>- И чем выразительней эта система [типов] и чем удачнее применяется, тем больше проблем выявляется при компиляции.


    Всё верно.

    Вся эта полемика уже сводится к:
    "
    A: Мультиметр полезная штука для некоторых задач — позволяет измерять напряжение, силу тока, сопротивление. Чем качественнее прибор — тем точнее результат.
    B: Я вот тут гвозди забиваю. Например вот так — БАХ, БАХ. Покажи чем мне тут поможет этот мультиметр.
    A: Для этой задачи не имеет смысла.
    B: АГА, шах и мат! "качественнее прибор — точнее результат", "некоторых задач" — всё это сказки про белого бычка!
    "


    EP>>Так ты определились, либо "целые классы ошибок" это сказки, либо нет и тебе просто не нравится количество этих классов, а конкретно их концентрация в одном примере из твоего опердня

    M>Мне не нравится, что высокопафосные заявления про, например, "на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time." скатываются в банальное «ну, главное чтобы килограммы с метрами не складывались»

    Так действительно, при наличии compile-time аргументов их можно использовать в сложных условиях. Например если есть compile-time массив, его можно отсортировать, делать двоичный поиск, и на основании результата разрешать или запрещать вызов конкретной функции. С чем не согласен-то?

    M>Этот весь «класс ошибок» является весьма маленьким.


    Уж точно не серебряная пуля от всех ошибок.

    M>Тебе не нравится пример из опердня, приведи ссылку на код не из опердня


    Чем тебе не нравится пример с аффинным пространством? Конкретный пример std::chrono — time_point и duration.
    http://en.cppreference.com/w/cpp/chrono
    Re[3]: Про типы и логику
    От: IT Россия linq2db.com
    Дата: 08.02.15 21:22
    Оценка: +3
    Здравствуйте, Mamut, Вы писали:

    M>Если эта задача настолько проста, что же апологеты типов не могут ее решить, несмотря на стопятьсот красивых текстов о том, как типы все решают?


    А смысл решать даже пусть теперь известно откуда выковырянные задачи? Мне такие задачи напоминают демонстрации от евангелистов. Берём примитивную задачу и показываем как круто она делается с помощью скажем Model First. Затем по максимуму снижаем акцент с "примитивная задача круто делается" и по максимум завышем его на "круто делается с помощью Model First". В результате получаем распиаренную технологию, которая к разработке реальных приложений не имеет никакого отношения.

    Ты пытаешься сделать тоже самое. Показать на примитивной задаче ненужность типов. При этом делая акцент не на примитивности, а на ненужности.

    IT>>Если ты когда-нибудь собирал мозаичные пазлы, то должен был заметить, что различная форма фрагментов рисунка позволяет избежать большинства ошибок и резко ускорить выполнение задачи. Типы в любой логике выполняют примерно туже самую роль.

    M>Демагогия.

    Ты слегка перепутал демагогию и аналогию. Демагогия — это способ ввести аудиторию в заблуждение. Аналогия, если она приводится в качестве пояснения, а не в качестве доказательства, помогает лучше понять предмет с помощью уже известных понятий. Будешь знать.

    Но продолжим аналогию. Ты фактически утверждаешь, что картинку можно просто разрезать на квадратики и не париться с пазлами и приводишь в качестве примера картинку из четырёх таких квадратиков. Ну хорошо, в этом случае наверное можно и не парится. Но что ты будешь делать с картитинкой в 1000 элементов? Если это будут квадратики, а не пазлы, то тебе потребуется на порядок больше времени.

    Типы — это дополнительный уровень верификации кода на самых ранних этапах возникновения проблемы. Те же юнит-тесты ловят последствия, типы позволяют устранить причину. Мне вообще странно слышать подобные разговоры от людей с опытом. То, что вы у себя в конторе научились есть кактус и при этом не сильно колоться, говорит лишь о вашем упёрстве и пониженном болевом пороге. Это очень круто. Примерно так же круто, как в цирке глотать шпаги или совать голову в пасть хищнику. И если бы вы со своим кактусом выступали в цирке, то я бы аплодировал стоя. Но в жизни то это нафига нужно?
    Если нам не помогут, то мы тоже никого не пощадим.
    Re: Про типы и логику
    От: kaa_t Россия  
    Дата: 19.03.15 15:12
    Оценка: 61 (2)
    Здравствуйте, Mamut, Вы писали:

    M>Выношу из соседнего обсуждения
    Автор: Mamut
    Дата: 02.02.15
    , так как там много флейма и отсутсвие конструктива.


    M>Мне просто действительно интересно. Многие утверждают, что типы помогают (чуть ли не) во всем, вплоть до того, что «тайпчекер проверяет именно логику».


    M>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить. Самое главное, если вся логика упаковывается в типы, каким образом проверяется правильность реализации этой логики на типах? Свое решение «в лоб» я тоже напишу, естественно Языки программирования — любые Но желательно приближенные к реальному миру (то есть те, что хоть в какой-то мере используются в природе).


    Сложность реализации логики на типах заключается в многословности. Если генерацию кода возложить на компилятор то вполне возможно реализовать. К примеру на Nemerle будет выглядеть как то так


    [ ЗаказМодель
        (
          Структура = ((Отправлен | Неотправлен) / ( Непредоплачен | Предоплачен ) ) / Риск,
          Операции  = 
          [ 
             Неотправлен(   СуммуУвеличить,СуммуУменьшить ),
             Непредоплачен (   СуммуУвеличить,СуммуУменьшить ),
             Отправлен ( СуммуУменьшить ),
          ]
          
          
        ) ]
      module Модель
      {
        
        
        шаблон_СуммуУвеличить_sum(sum:decimal,val:decimal):decimal
        {
          if (sum + val > 2000 ) sum else sum + val 
        }
        
        шаблон_СуммуУменьшить_sum(sum:decimal,val:decimal):decimal
        {
          sum - val
        }
      }


    это декларативное описание макросом будет развернуто приблизительно в такой код:

      module Модель
      {
        [Record]
        public variant Заказ
        {
          | Отправлен
          {
            public ЗаказНепредоплачен():Заказ.ОтправленНепредоплачен
            {
              Заказ.ОтправленНепредоплачен(sum)
            }
            public ЗаказРиск():Заказ.ОтправленРиск
            {
              Заказ.ОтправленРиск(sum);
            }
            public СуммуУменьшить(val:decimal):Отправлен
            {
              def funct( sum:decimal,val:decimal):decimal
              {
                sum - val
              } 
              Отправлен(funct( sum, val ))
            }
          }
          | ОтправленНепредоплачен {  .... }
          | ОтправленРиск {  ... }
    
          .....    
          
          public Сумма:decimal {  get { sum } }
          
          private mutable sum:decimal;
          
    
          public static УменьшитьСумму( zlist : list[Заказ] , val:decimal ) : list[Заказ]
          {
            zlist.Map(z=> 
            {
              match(z)
              {
                | e is Отправлен =>  e.СуммуУменьшить(val);
            .....
    
                | _ => z;
              }
            })
          }
        }
      }


    собственно основная сложность состоит не в реализации кода макроса. Сложно придумать декларативный язык, который адекватно опишет модель
    Re: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 09:22
    Оценка: 48 (2)
    Одна из проблем, в котором я столкнулся в обсуждении в соседней ветке — это какой-то мегастранный подход апологетов типизации к решению задачи. Почему-то несколько раз для них являлось откровением, что все проверки можно и нужно делать не в местах, откуда вызывается change_amount, а внутри самой функции change_amount. Или, например, что в таком случае можно возвращать внятные ошибки

    Несмотря на жалобы IT
    Автор: IT
    Дата: 06.02.15
    , эта задача — реальная задача, решаемая нашей компанией тысячи раз в день. Выросла она на основе тех самых "ad-hoc and often informal specifications", о которых говорится в презентации тут
    Автор: jazzer
    Дата: 30.01.15
    . Почему-то, несмотря на презентацию, и уверенность в «компиляторе, проверяющем мозаику», никто так и не осилил решить эту задачу типами

    Вы думаете, задачи в Standard Chartered Bank сильно отличаются от такой? Вы сильно заблуждаетесь.

    В общем, решение в лоб. Примерно в таком виде оно существует и у нас, работает, проблем не вызывает. Изменение суммы производится путем вызова order:change_amount. Эта функция вызывается из трех мест. Все, что в нее передается — это заказ и новая сумма. На выходе — {ok, UpdatedOrder} или {error, Reason}.

    Код полупсевдокод (знающие Erlang поймут, почему — в if guard'ах нельзя кастомные функции). Код писал вручную прямо в редакторе сообщений RSDN, так что могут быть ошибки, естественно

    Естественно, к коду еще будут приложены тесты, проверяющие ожидаемое поведение для заказов в разных состояниях. Как unit-тесты, проверяющие, правильно ли реализована функция, так и integration-тесты, проверяющие поведение всей системы. А у вас не так?

    M>Шаг 1.


    M>[*] если заказ неотправлен и непредоплачен, можно увеличивать и уменьшать

    M>[*] если заказ отправлен, нельзя увеличивать, можно уменьшать
    M>[*] если сумма увеличивается, мы должны провести risk check. если risk check не проходит, товар никак не помечается, но изменение суммы не проходит
    M>[*] если товар помечен, как risk, то изменять сумму нельзя

    change_amount(Order, NewAmount) ->
      case is_forbidden(Order, NewAmount) of
        {error, Reason} ->
          {error, Reason};
        ok ->
          case risk_check(Order, NewAmount) of
            {error, Reason} -> {error, Reason};
            ok -> {ok, Order#order{amount = NewAmount}
          end
      end.
    
    is_forbidden(Order, NewAmount) ->
      if
        is_risk(Order) ->
          {error, risk};
        not is_shipped(Order) andalso not is_prepaid(Order) ->
          ok;
        is_shipped(Order) andalso NewAmount > amount(Order) ->
          {error, amount}
        true ->
          ok
      end.
    
    risk_check(Order, NewAmount) ->
      case amount(Order) < Amount of
        true -> risk:risk_check(Order, Amount);
        ok
      end.



    M>Шаг 2.


    M>Изменение суммы:


    M>Все то же самое, что и в шаге первом, только:


    M>[*] увеличивать можно на max(фиксированная сумма1, процент1 от оригинальной суммы заказа)

    M>[*] уменьшать можно на max(фиксированная сумма2, процент2 от оригинальной суммы заказа),
    M>где сумма1, сумма2, процент1, процент2 — это конфигурация, считываемая из базы данных

    M>Если изменение не попадает в эти рамки, то увеличить/уменьшить нельзя


    Добавляется одна функция и вызов этой функции. Все остальное без изменений.

    change_amount(Order, NewAmount) ->
      case is_forbidden(Order, NewAmount) of
        ...
        ok ->
          case risk_check(Order, NewAmount) of
            ...
            ok -> 
              update_amount(Order, NewAmount)
          end
      end.
    
    ...
    
    update_amount(Order, NewAmount) when amount(Order) > NewAmount ->
       Estore = get_estore(Order)
       Max = config:read(Estore, max_decrease),
       MaxPct = config:read(Estore, max_increase_pct),
       AmountDiff = abs(amount(Order) - NewAmount),
    
       case AmountDiff > Max andalso AmountDiff/amount(Order) > MaxPct of
         true -> {error, amount};
         false -> {ok, Order#order{amount = NewAmount}}
       end;
    update_amount(Order, NewAmount) ->
       %% то же самое, только для max_increase и max_increase_pct
       end.


    M>Шаг 3.


    M>Все то же самое, что и в шаге 2. Дополнительно:


    M>[*] если заказ предоплачен (неважно, отправлен или нет), можно увеличивать сумму, если это разрешено конфигурацией магазина. Сумма, на которую можно увеличивать высчитывается, как в шаге 2

    M>[*] если заказ предоплачен, неотправлен, и сумма увеличивается, надо сделать auth-запрос в банк. если он не срабатывает, увеличить нельзя.
    M>[*] если заказ предоплачен, отправлен, и сумма увеличивается, надо сделать auth-запрос в банк на разницу в сумме, а потом сделать capture запрос на всю сумму. Если хоть один из них не срабатывает, увеличить нельзя.

    Меняются некоторые условия, добавляются функции. В реальности проверок is_forbidden еще около десятка. Полный код.

    change_amount(Order, NewAmount) ->
      case is_forbidden(Order, NewAmount) of
        {error, Reason} ->
          {error, Reason};
        ok ->
          case risk_check(Order, NewAmount) of
            {error, Reason} -> {error, Reason};
            ok -> update_amount(Order, NewAmount)
          end
      end.
    
    is_forbidden(Order, NewAmount) ->
      if
        is_risk(Order) ->
          {error, risk};
        is_prepaid(Order) andalso NewAmount > amount(Order) ->
          can_raise_prepaid_order(Order, NewAmount);
        is_shipped(Order) andalso NewAmount > amount(Order) ->
          {error, amount}
        true ->
          ok
      end.
    
    can_raise_prepaid_order(Order, NewAmount) ->
      Estore = get_estore(Order),
      case config:get_config(Estore, can_raise_prepaid) of
        false -> {error, amount};
        true -> ok
      end.  
    
    risk_check(Order, NewAmount) ->
      case amount(Order) < Amount of
        true -> risk:risk_check(Order, Amount);
        ok
      end.
    
    update_amount(Order, NewAmount) ->
       Estore = get_estore(Order)
       Max = config:read(Estore, case amount(Order) > NewAmount of true -> max_decrease; false -> max_increase end),
       MaxPct = config:read(Estore, case amount(Order) > NewAmount of true -> max_decrease_pct; false -> max_increase_pct end),
       AmountDiff = abs(amount(Order) - NewAmount),
    
       case AmountDiff > Max andalso AmountDiff/amount(Order) > MaxPct of
         true -> {error, amount};
         false -> 
            auth_and_capture(Order, NewAmount)
       end.
    
    auth_and_capture(Order, NewAmount) ->
      case is_prepaid(Order) of
        false ->
          {ok, Order#order{amount = NewAmount};
        true ->
          case NewAmount > amount(Order) of
            true ->
              case payments:auth(Order, NewAmount - amount(Order)) of
                {error, Reason} -> {error, Reason};
                ok -> capture(Order, NewAmount)
              end;
            false ->
               capture(Order, NewAmount)
          end
      end.
    
    capture(Order, NewAmount) ->
      case is_shipped(Order) of
        false -> {ok, Order#order{amount = NewAmount};
        true ->
          case payment:capture(Order, NewAmount) of
            {error, Reason} -> {error, Reason};
            ok -> {ok, Order#order{amount = NewAmount}
          end
      end.


    dmitriid.comGitHubLinkedIn
    Re: Про типы и логику
    От: kaa.python Ниоткуда РСДН профессионально мёртв и завален ватой.
    Дата: 06.02.15 02:19
    Оценка: 43 (2)
    Здравствуйте, Mamut, Вы писали:

    M>Выношу из соседнего обсуждения
    Автор: Mamut
    Дата: 02.02.15
    , так как там много флейма и отсутсвие конструктива.

    M>Мне просто действительно интересно. Многие утверждают, что типы помогают (чуть ли не) во всем, вплоть до того, что «тайпчекер проверяет именно логику».

    Типы очень хорошая штука и, как мне кажется, формально можно сказать что они проверяют логику. Думаю очевидно что наличие информации о типах на этапе компиляции позволит избежать обычных синтаксических ошибок, последствий рефакторинга, неверной трактовки пришедшего типа переменной. Фактически, это и есть проверка твоей логики, т.к. ты уверен что "данная функция не предпримет недопустимых действий над пришедшими данными".

    В приведенном тобой примере, логику на типах, само собой не закодируешь, но они однозначно упростят рефакторинг, позволят не писать ряд тестов для проверки корректности поведения с не подходящими типами да и IDE будет проще разобраться с тем что происходит.

    Само собой, если язык легко позволяет творить с типами что угодно через приведение к void*, то мы получаем дополнительные места с неочевидным поведением, но они хотя бы локализованны и и проще покрыть тестами.

    Как-то так...
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 12:32
    Оценка: 30 (1) :)
    M>>Хотя да, скажем передвижение заказа по dunning'у у нас описано развесистой машиной состояний, с интересными проверками там и тут и прочими плюшками.
    S>Что-то такое тоже есть в паре мест. Особенно удобно в отладочных сборках навесить на изменение текущего состояния все возможные проверки. Пару раз спасало от багов из разряда "фиг найдёшь".

    У нас в итоге «фиг найдешь баги» появились из-за новых требований к определенному классу заказов.

    То есть в целом для dunning'а не имеет значения, кто и когда откуда заказ сделал, главное — какой способ оплаты выбран. И потом заказ перемещается по состояниям A -> B -> C -> D и т.п.

    Но появился новый тип интеграции в котором как всегда ВНЕЗАПНО (a.k.a. ad-hoc) надо было поломать state-машину примерно так:
    
    A -> B -> C  -> D -> E -> F
         \              /
          -(if X) - - -



    Это обходило пару проверок, которые были указаны в C и D, и которые рушили представления о заказе, когда заказ из F, например, перемещался обратно в C. И таких сокращений из-за новой интеграции было несколько штук Слава богу, когда от интеграции отказались, вычищать эти проблемы пришлось не мне


    dmitriid.comGitHubLinkedIn
    Re[3]: Про типы и логику
    От: Sinix  
    Дата: 06.02.15 11:03
    Оценка: 27 (2)
    Здравствуйте, Mamut, Вы писали:

    S>>Я видно не понимаю контекста, но зачем тут именно типы?


    M>Ну, ту просто в соседней теме мне все уши прожужжали, как надо всю логику класть в типы, как это все прекрасно проверится при компиляции и т.п. Вот я не выдержал и свел воедино одну достаточно простую задачу.

    А, тогда ой. Я что-то не соображу, что тут можно придумать кроме очевидных и нужных not-null и типов-размерностей. Тоже интересно было бы посмотреть.

    S>>Для чего-то покритичнее нужны контракты + ...

    M>Ой 0_о
    Ага Даже простые trait/variant особо популярности не набрали, что уж тут говорить о статической верификации на типах.

    Я кстати уже который год внимательно смотрю за CodeContracts. Очень интересная попытка протащить статические контракты в мейнстрим малой кровью. Поначалу "малой кровью" не выходило, контракты надо было прописывать в каждом методе (и обновлять всю цепочку вызовов при любом изменении контракта). Плюс куча мелких косяков реврайтера, плюс поддержка только премиум-версии студии и тыды и тыпы.
    Короче, штука только для поиграться была.

    А где-то год назад в контракты добавили автоматический вывод контрактов и к прошлой осени допилили его до практически рабочего состояния. Например:
        static void Example()
        {
            // Warning: CodeContracts: requires is false: !string.IsNullOrEmpty(s).
            // This sequence of invocations will bring to an error Example -> TestWithContract -> TestWithContract2 -> TestWithContract3 -> TestWithContract4, condition !string.IsNullOrEmpty(s)
            TestWithContract(""); 
        }
        
        private static void TestWithContract(string s)
        {
            TestWithContract2(s);
        }
        private static void TestWithContract2(string s)
        {
            TestWithContract3(s);
        }
        private static void TestWithContract3(string s)
        {
            TestWithContract4(s);
        }
        private static void TestWithContract4(string s)
        {
            TestWithContractCore(s);
        }
        private static void TestWithContractCore(string s)
        {
            Contract.Requires(!string.IsNullOrEmpty(s));
            Console.WriteLine(s);
        }

    + поддержка в VS Community + недавное выкладывание CC в опенсорс... молодцы, короче

    Два недостатка:
    * не работает вывод по if-then-throw, только для контрактов через Contract.Requires(),
    * сборка с проверкой всех контрактов может занимать дофигищща времени.
    Ну, и надо аккуратно настраивать параметры верификации для каждого проекта + повозиться с билд-сервером, но это уже мелочи.

    Уже всерьёз думаю полноценно опробовать в продакшне, если будет возможность


    M>Ну, в целом я на самом деле согласен. У нас, правда, данный конкретный случай решено, по сути, if'ами В change_sum там три функции is_fobidden_1, is_fobidden_2 и is_fobidden_3 где-то на сто строчек После чего происходит собственно увеличение суммы (которое тоже может происходить по-разному из-за всякого разного).


    Угу. В текущем проекте контракты не используются, зато вовсю используются отладочные ассерты. Безумно удобная штука: пишешь код, закладываешься на какое-то поведение (например, на order.State == State.Processed), добавил в код что-то типа
    DebugCode.AssertBusiness(order.State == State.Processed, "бла-бла-бла");

    и где-то через год-полтора, когда в метод всё-таки умудрятся продавить сырой заказ, ошибка всплывёт сразу при тестировании (в худшем случае — у тестера), а не уйдёт заказчику.

    Если проверки совсем критичные, то можно оставить ассерты и в релизной версии, но как правило большая часть условий из релизной версии убирается, т.к. нужны только для отладки.

    M>Хотя да, скажем передвижение заказа по dunning'у у нас описано развесистой машиной состояний, с интересными проверками там и тут и прочими плюшками.

    Что-то такое тоже есть в паре мест. Особенно удобно в отладочных сборках навесить на изменение текущего состояния все возможные проверки. Пару раз спасало от багов из разряда "фиг найдёшь".



    S>>Не, при желании система типов может быть расширена так, чтобы передаваемое значение аннотировалось контрактами метода, этакий adt на стероидах. Но на практике это приведёт к дичайшему гемморою из-за high cohesion: контракты расползаются по всему коду и поменять их ничего не поломав — тот ещё квест.


    M>Ой. А мне утверждали, что придется меняться не во всем коде, а только в одном месте

    Проблемы с расползанием будут, если контракты прописывать явно, как у тебя в стартовом сообщении. А если выводить автоматически (что насколько я знаю, умеет только code contracts, по крайней мере из более-менее мейнстрима) — то совсем другое дело
    Re: Про типы и логику
    От: Слава  
    Дата: 07.02.15 06:01
    Оценка: +1 -1
    Здравствуйте, Mamut, Вы писали:

    С интересом прочитал весь тред, надеясь увидеть решение на типах. К сожалению, не увидел. Эх...
    Re[8]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 09:33
    Оценка: -1 :)
    M>>Можно увидеть на деле то, что описано в корневом сообщении этого топика? Я за пять минут написал свое решение. Ни один из апологетов типов не осилил написать это решение

    EP>Я сразу сказал, что в данной постановке это не имеет смысла:

    EP>

    EP>>Если же для запуска функции нет необходимости делать проверки, change_amount сама всё что нужно проверяет внутри, и более того её запуск с невыполненными условиями не является ошибкой, а вполне штатным режимом — то пытаться переписать все эти внутренние проверки на типы, не вижу смысла, это никак не отразится на местах вызова этой функции.



    Да, но ничего не изменилось. Цепочка условий и прочая и прочая так и остались, просто сместилась точка вызова


    M>>только отмазки, рассказы про то, как все будет хорошо,


    EP>Твои фантазии.


    M>>и наугад вырванные отдельные куски условий с заявлениями «видишь, как все хорошо»?


    EP>Это куски из других задач, с другой постановкой. Почему тут приводятся, читай рядом с самими кусками, например:

    EP>

    EP>>В предыдущей теме, в некоторых местах

    разговор шёл именно о предварительных проверках, а не внутренних:


    Потому что ты решил, что задача так поставлена. Разницы между задачей в этом топике и изначальным описанием
    Автор: Mamut
    Дата: 03.02.15
    примерно ноль. Ну, вернее разница лишь в том, что задача в этом топике — это развернутое описание второго пункта. Все твои бурные фантазии про пред-пост-над-под-из-за-условия — лишь твои бурные фантазии.


    dmitriid.comGitHubLinkedIn
    Re[4]: Про типы и логику
    От: Кодт Россия  
    Дата: 09.02.15 10:25
    Оценка: +2
    Здравствуйте, Abyx, Вы писали:

    A>а что именно ты хочешь? полиморфизм?


    Полиморфизм можно или в рантайм вытащить — вариантные типы, кортежи с признаками, старое доброе ООП (GADT для любителей хаскелла), наконец; или вывернуть красную шапочку мясом наружу, сделать всё на продолжениях.
    Тут — кому что эстетичнее. И какой язык подо что заточен.


    A>или тебе надо статическую проверку типов?


    В конце концов, достаточно мощный статический анализатор может бить по пальцам за assertion failed, если рантаймовый код достаточно прозрачен.
    Перекуём баги на фичи!
    Re[5]: Про типы и логику
    От: IT Россия linq2db.com
    Дата: 09.02.15 23:19
    Оценка: +2
    Здравствуйте, Mamut, Вы писали:

    IT>>Ты пытаешься сделать тоже самое. Показать на примитивной задаче ненужность типов. При этом делая акцент не на примитивности, а на ненужности.

    M>Нет, не пытаюсь. Я пытаюсь выбить из апологетов типов что-то большее,

    Выбивают обычно показания, причём желательно устраивающие выбивающего. Впрочем, именно этим ты тут и занимаешься. Тебя же ведь не интересует истина, правда? Тебе же нужно по любому отстоять своё мнение.

    M>Не нравится эта задача — предложи/покажи другую задача. В чем проблема-то?


    Такой пример тебя устроит?

    t.FirstName++;


    M>Опять — тонны текста, демагогия, аналогии и рассказы о том, каким мы тупые, с нашим кактусом. Извини. Это — не аргументация.


    Мамут, ты уже задолбал подобными аргументами. Тебе в каждом сообщении мерещатся только тонны текста, демагогия, жалобы и рассказы. Давай уже меняй пластинку. И ещё сходи почитай хотя бы в туже википедию определение демагогии.

    По поводу типов повторюсь ещё раз. Мне очень странно слыашать подобные разговоры от человека с опытом. Ты споришь с основами мироздания в программировании. С аксиомами. Это даже доказывать не надо. Ты пойми, как параллельные прямые не пересекаются, так и типизация устраняет причины возникновения ошибок, связанных с типами. Ты бы ещё начал доказывать, что если "Hello, world" можно написать в notepad, то всякие вижуал студии и решарперы овно, никому не нужны и даже вредны.
    Если нам не помогут, то мы тоже никого не пощадим.
    Re[12]: Про типы и логику
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 14.04.15 12:09
    Оценка: +2
    Здравствуйте, alex_public, Вы писали:

    _>Так я же не спорю, а как раз наоборот выясняю детали его задачи. Ну отлично, если строго одна элементарная операция на транзакцию, то я особого смысла в программирование на типах тут не вижу.

    Но проблемы противоречивости-то никуда не делись.

    Более-менее популярный пример: есть, скажем, банальный push-код типа:
    public void PushDataToStream(StreamWriter w)
    {
       var r = File.OpenRead("EULA.txt");
       try
       {
          foreach(var line in r.RealAllLines)
             w.WriteLine(r)
       }
       finally
       {
         r.Close(); // критический код, который мы хотим обязательно выполнить.
       }
    }


    Предположим, что мы хотим переписать его в pull-код, т.е. в пассивный режим.
    На традиционных ЯП мы будем реализовывать интерфейс типа string GetNextLine(void).
    И дупа — в том, как нам это сделать, сохранив гарантии про выполнение r.Close().

    Конкретно C# конкретно эту проблему решает. Что показывает — несмотря на то, что монолитный код превратился в множество вызовов, по-прежнему можно вести речь об осмысленных гарантиях.
    Так и в обработке ордеров: то, что обработка заказа — это не один метод с множеством ветвлений, а множество вызовов множества методов, никак не отменяет наличия интересных инвариантов, которые хочется контролировать статически.

    _>P.S. Да, кстати, а мне казалось, что как раз использование транзакций (которые в БД) и позволяет не беспокоиться о проблемах при сбоях посередине длинной последовательности операций. Ну да ладно...

    Да, вам казалось.
    Уйдемте отсюда, Румата! У вас слишком богатые погреба.
    Re: Про типы и логику
    От: Sinix  
    Дата: 05.02.15 17:05
    Оценка: 38 (1)
    Здравствуйте, Mamut, Вы писали:

    M> меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить. Самое главное, если вся логика упаковывается в типы, каким образом проверяется правильность реализации этой логики на типах?

    Я видно не понимаю контекста, но зачем тут именно типы?

    Для примитивного опердня за глаза хватит обычных ассертов.

    Для чего-то покритичнее нужны контракты + smt-солвер для верификации пост/предусловий + ассерты, чтобы покрыть условия, которые солвер не может вывести автоматически. Или (вариант для бедных), реврайтер чтобы подставлять условия-инварианты в каждый метод + тесты с более-менее полноценным покрытием кода.

    Не, при желании система типов может быть расширена так, чтобы передаваемое значение аннотировалось контрактами метода, этакий adt на стероидах. Но на практике это приведёт к дичайшему гемморою из-за high cohesion: контракты расползаются по всему коду и поменять их ничего не поломав — тот ещё квест.
    Re: Про типы и логику
    От: Кодт Россия  
    Дата: 06.02.15 13:39
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    M>Собственно задача. Мы будем эмулировать реальную разработку, в которой требования меняются. Мне интересно, как будет меняться реализация с типами по мере изменения требований. Все крутится вокруг изменения суммы. Для спортивности: не смотрите в следующий шаг, пока не реализован первый шаг.


    Если с самого начала знать, что шаги будут "в ассортименте", то можно упаковать все условия в утино-типизированный кортеж времени компиляции.
    Тогда получишь фантомные типы вокруг одного и того же нетто-типа.

    template<class Netto, class Phantom> struct phantom_type
    {
      typedef Phantom phantom;
      Netto value;
      phantom_type(Netto v) : value(v) {}
    };
    
    // нетто
    typedef int Good; // товар (в штуках)
    
    // операции
    unspecified1<Good> start(Good value);
    unspecified1<Good> increase(unspecified0<Good> good);
    unspecified1<Good> decrease(unspecified0<Good> good);
    unspecified1<Good> increase(unspecified0<Good> good);
    unspecified1<Good> riskcheck(unspecified0<Good> good); // здесь мы влезаем в полиморфизм времени исполнения
                                                           // так что - или делаем на продолжениях, или на полиморфных значениях
    unspecified1<Good> pay(unspecified0<Good> good);
    unspecified1<Good> send(unspecified0<Good> good);


    Как это сделать _красиво_ — тут надо подумать.
    То, что потребуются функторы — безусловно.
    Какой-то небольшой фреймворчик, реализующий аппликативные функторы. В хаскелле, так, всё из коробки будет (я так думаю), а камле, скале и плюсах придётся немножко попотеть.
    Перекуём баги на фичи!
    Re[4]: Ах да, забыл
    От: Кодт Россия  
    Дата: 06.02.15 16:36
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    M>Но пока что никто не рискнул Даже у Кодта наметки
    Автор: Кодт
    Дата: 06.02.15
    , но без продолжения (но он объяснил, почему).


    Я начал писать, но понял, что можно сделать красивее, но когда начал переписывать, увидел, что можно ещё красивее сделать... Ну и отвлёкся на поработать.

    Там конструкция примерно такая выходит
    template<class PT> struct match_phantom;
    template<class N, class P> struct match_phantom<phantom_type<N,P>> { typedef N n_type; typedef P p_type; };
    
    template<class PT> using phantom<PT> = match_phantom<PT>::p_type;
    template<class PT> using net<PT> = match_phantom<PT>::n_type;
    template<class PT, class P1> using update_phantom = phantom_type<net<PT>, P1>;
    
    
    template<class Final> struct applicator
    {
      template<class PT> using asserted_and_transformed = 
        enabled_if<
          Final::precondition<phantom<PT>>::value, // выковыриваем признаки и проверяем предусловие
          update_phantom<PT, Final::transform<PT>> // получаем новые признаки и пришиваем к типу
        >;
    
      static template<class PT> auto action(PT pt) -> asserted_and_transformed<PT>
      { return Final::work(pt.value); }
    };
    
    struct IdentityFunctor : application<SomeFunctor>
    {
      template<class Phantom> using precondition = mpl_bool<true>;
      template<class Phantom> using transform    = Phantom;
      static Good work(Good value) { return value; }
    };
    
    
    
    // признаки, которые нам нужны на первом шаге - пока что свалю в кучу
    struct just_started
    {
      static bool is_paid = false;
      static bool is_sent = false;
      static bool is_increased = false;
      static bool is_checked = true;
    };
    
    
    struct Start : applicator<Start> // прикрутим сюда функтор через CRTP
    {
      // внутренние
      template<class P> using precondition = is_same<P,void>; // для затравки
      template<class P> using transform = just_started; // начинаем с вот таких признаков - создаём вот такой фантом
      static Good work(Good value) { return value; } // функция, которую будем лифтить; по умолчанию, id-функцию можно взять из коробки, из applicator.
    };
    
    struct Send : applicator<Send>
    {
      template<class P> using precondition = mpl_bool<P::is_paid && P::is_checked>; // тупой предикат: взять булеву константу из признаков
      template<class P> struct transform : P { static bool is_sent = true; }; // по-простому, сокрытием имён ввели новое значение
    };
    
    struct Increase : application<Increase>
    {
      template<class P> using precondition = mpl_bool<!P::is_sent>;
      template<class P> struct transform : P
      {
        is_checked = !P::is_sent;
        is_increased = true;
      };
      static Good work(Good value) { return value+1; }
    };


    Что-то в таком ключе.
    Дальше — в зависимости от диалекта. На 98 плюсах будет много слов, на 11 — мало, на 14 — совсем мало.


    Как видишь, тут и наглядность не страдает, и кастомизабельность — как следствие — достаточно высокая.
    И несложно растащить функции (XXX::work) и метафункции (XXX::precondition, XXX::transform)

    Возможно, что в бусте уже всё придумано за нас. А если не придумано, допилю и выложу в продакшен
    Перекуём баги на фичи!
    Re[2]: Ах да, мое решение :)
    От: artelk  
    Дата: 06.02.15 19:55
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    Вижу пачку предикатов на (Order, NewAmount), возвращающих (ok | (Error, Reason)).
    Как вариант, можно было, например, сделать, чтобы вместо ok возвращался "помеченный" Order:

    data CanUpdateAmountOrder = CanUpdateAmountOrder Order NewAmount
    
    can_update_amount :: (Order, NewAmount) => Either (CanUpdateAmountOrder Order NewAmount) (Error, Reason)
    can_update_amount = ...


    Далее поменять update_amount, чтобы принимал параметром этот CanUpdateAmountOrder, тем самым заставляя проверять этот предикат везде, где update_amount вызывается.
    Во всех функциях, имеющих смысл только для заказов, у которых можно менять amount также меняем тип параметра.

    В идеале хотелось бы, чтобы можно было "помечать" тип произвольной комбинацией аттрибутов и чтобы можно было сказать компилятору, что в функцию foo можно передавать только Order, помеченный аттрибутами A,B и C, а в функцию bar — помеченный C и D, так что если у нас есть Order, помеченный A, B, C и D, то его можно передать в обе функции и т.п. Не знаю, можно ли такой сделать на Хаскеле или C++. Зависимыми типами и прочими liquid types пахнет... )
    Re: Про типы и логику
    От: koodeer  
    Дата: 07.02.15 08:24
    Оценка: 21 (1)
    Здравствуйте, Mamut.

    Уважаемый, я вот что скажу. Качественных примеров на типах мы в этом треде вряд ли дождёмся по простой причине: пока что не наработаны методики написания такого кода. Вот, например, когда появилось ООП, то далеко не сразу народ стал активно (а главное — правильно!) его использовать. Нужно подождать. С течением времени появятся новые методики и паттерны, качественная поддержка в компиляторах и IDE, а также опыт разработчиков.
    Re[5]: Про типы и логику
    От: os24ever
    Дата: 07.02.15 20:18
    Оценка: 21 (1)
    M>Можно код полностью, пожалуйста? А то «добавь тут, добавь там, допущены к исполнению» — это как-то сверх-абстрактно
    Флажки будет проверять функция:
    order_is(Tuple, Element) -> 
      lists:member(Element, tuple_to_list(Tuple)).

    Её заголовок будет таким:
    approve({order, {data, D}, {flags, F}}) when order_is(F, checked) -> 
      % 
      % До этого места дойдём только если в кортеже {order, {data, ...}, {flags, ...}} 
      % есть кортеж {flags, ...} и в нём есть элемент checked, то есть если он выглядит 
      % как {flags, ..., checked, ..., ..., ...} 
      % 
    
    .

    А вызывать её будем так:
    case approve(Order) of
      {ok, ...} ->
           ...
      _ ->
          exit(badOrderstState)
    end.

    По аналогии с операторами в C, переключающими и проверяющими битовые флажки.
    Только здесь при добавлении/отключении флажка придётся заново создавать новый кортеж Order.
    Re[6]: Ах да, забыл
    От: Кодт Россия  
    Дата: 09.02.15 10:11
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    К>>Как видишь, тут и наглядность не страдает, и кастомизабельность — как следствие — достаточно высокая.


    M>Ээээ, что? Я, конечно, дааавненько на C++ не смотрел, но разобраться во всех этих шаблонах и зависимостях для меня проблема. Скажем, я тут вообще не понимаю: и что же дальше


    Там две части.
    Первая — это фреймворк для создания функтора "фантомный тип".
    Вторая — это, собственно, программа. Начиная с "// признаки, которые нам нужны на первом шаге — пока что свалю в кучу"

    Дальше получается так
    auto good_1 = Start::action( phantom_type<Good,void>(1) ); // положили товар в корзину; тип - phantom_type<Good,just_started>
    auto good_2 = Pay::action( good_1 ); // оплатили: phantom_type<Good, {just_started, is_checked=true, is_paid=true} >
    auto good_3 = Increase::action( good_2 ); // добавили: phantom_type<Good, {just_started, is_checked=false, is_paid=true} >
    auto good_4 = Pay::action( good_3 ); // оплатили добавку
    auto good_5 = Send::action( good_4 ); // отправили


    M>По-моему, чтобы такое написать, надо быть семи пядей во лбу


    Не семи пядей. Просто мне было лень тащить буст (там в mpl можно много чего сделать), и я руками минимум-миниморум наколбасил.


    К>>И несложно растащить функции (XXX::work) и метафункции (XXX::precondition, XXX::transform)

    M>Я за 10 минут растащил все это без шаблонов

    Так, небось, всё в рантайме сделал на эрланге. В рантайме-то любой дурак сделает.

    К>>Возможно, что в бусте уже всё придумано за нас. А если не придумано, допилю и выложу в продакшен


    M>Да, хотел бы посмотреть на результат Надо не забывать, из всего этого еще внятные ошибки хотелось бы возвращать


    Статик ассерты наше всё. Но над этим надо поработать.
    Перекуём баги на фичи!
    Re[13]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 10.02.15 06:24
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    M>>>Предложи задачу, для которой имеет

    EP>>Для тех задач где есть какие-то предусловия:
    M>В первом же сообщении этой темы есть задача, где эти предусловия есть. То есть до того, как мы собственно меняем amount, у нас идет толпа предусловий

    Вот если бы это изменение amount, с предусловиями, многократно использовалось в разных местах — то какой-то смысл был бы.
    А так получится явно более громоздко чем твой вариант

    EP>>
    EP>>template<typename State>
    EP>>enable_if_t
    EP>><
    EP>>    State::prepared && State::risk_checked || State::approved_by_boss
    >>> change_amount_unconditionally(Order<State> x, Money amount)
    EP>>{
    EP>>    // ...
    EP>>}
    EP>>

    M>Можно мне наконец увидеть полное решение задачи в корневом сообщении

    В n-ый раз повторю — для неё не имеет смысла. Ведь ты же хочешь сравнить два решения, так?
    Не вижу смысла сравнивать "кодирование логики на типах" против варианта без этого на задаче где эта самая логика на типах не имеет смысла.
    Если же тебе нужен просто сферический пример предусловий на типах — смотри пример кода выше. Если же нужны пояснения/дополнения по коду — то спрашивай.

    M>со всеми этими enable_if_t?


    enable_if_t — это вообще стандартная утилита.
    http://en.cppreference.com/w/cpp/types/enable_if

    EP>>Runtime данные можно переводить в compile-time, причём данные любой сложности, об этом я неоднократно говорил в предыдущем топике, и даже приводил конкретный код. Вопрос упирается в code-bloat.

    M>Можно ссылку на конкретный код? Потому что я помню только куски кода, которые разваливались от банального вопроса типа «а что будет, если у нас немного больше условий, чем проверка на одно состояние».

    Уже многократно приводил: http://rsdn.ru/forum/cpp/5824553.flat
    Автор: Кодт
    Дата: 20.10.14

    Вкратце есть два основных варианта.
    Первый это continuation-passing style, например:
    template<typename F>
    void read_order(F f)
    {
        bool is_prepared = read_bool();
        if(is_prepared)
            f(Order<true>{});
        else
            f(Order<false>{});
    }
    // Example of usage:
    {
        read_order([](auto order)
        {
            use(order)
        });
    }

    Второй это varaint либо аналоги:
    variant<Order<true>, Order<false>> read_order()
    {
        bool is_prepared = read_bool();
        if(is_prepared)
            return Order<true>{};
        else
            return Order<false>{};
    }
    // Example of usage:
    {
        auto x= read_order();
        // ...
        apply(x, [](auto order)
        {
            use(order)
        });
    }

    Если в этих примерах функция use принимает только конкретный Order<true>, то на этапе компиляции появится ошибка при передачи Order<false>, и в этом случае пользователь функции use будет вынужден отфильтровать типы order'ов, например через pattern matching перегрузкой.

    Причём всю эту десериализацию из runtime в compile-time можно автоматизировать посредством мета-программирования.

    M>>>Отлавливается первым же залетным тестом

    EP>>Mars Climate Orbiter тесты не спасли. Хотя, по всей видимости, тестировалось всё более пристрастно чем типичный опердень.
    EP>>Image: mars98orb.jpg
    M>В зависимости от реализации, типы тоже могут нифига не спасти

    Отчего же? Если бы в интерфейсе у них было не просто float/double, а конкретные единицы измерения — то проблему можно было бы избежать.

    M>Классический пример, у нас был, кстати. Идет общение со сторонним сервисом. Мы отдаем JSON, та сторона принимает JSON. Наша сторона банально пакует данные в JSON и отправляет. На той стороне JSON принимается, распаковывается и используется.

    M>Ну, с нашей стороны приходит валидный объект, генерируется валидный JSON, но в какой-то момент все ломается Принимающая сторона решила, что теперь поле X должно быть не числом, а строкой

    В таких случаях код сериализации нужно генерировать из общей схемы, причём желательно включать номер ревизии этой самой схемы в передачу.

    M>>>Ну да, при рефакотринге будет приятно. В реальных задачах будет занимать мизерную часть проблем.

    EP>>И даже 100% покрытие строчек кода тестами не даёт гарантии что все ошибки этого класса найдены.
    M>100% покрытие типами вообще не дает никакой гарантии, что код вообще правильный

    А в случае с типам некоторые гарантии появляются.

    M>Могу только повторить. У нас самые главные проблемы — это бизнес-логика, а не несоответсвие килограммов с километрами


    Я не знаю что конкретно ты называешь бизнес-логикой, но для меня несоответствие килограммов с километрами это проблема из предметной области.

    M>В общем, этот рассказ не столько против типов, сколько про то, что типы наверняка помогут сделать правильный DSL. Но потом в этот DSL начинает приходить все, что угодно, и вылетать оно будет, как назло, в рантайме


    Я говорил не просто про DSL, а про Embedded Domain Specific Language, Boost.Proto как раз про это.
    То есть в C++ встраивается под-язык какой-то предметной области. И система типов помогает отлавливать грамматические ошибки в этом самом EDSL на этапе компиляции.
    Re[15]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 10.02.15 10:21
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    M>Ну то есть типы помогают только при copy-paste based programming'е? Как только одинаковые «предусловия» из ста мест переносятся в один вызов API, они сразу становятся ненужны и «более громоздки»?


    Опять таки, считай что при каждом вызове типизированной функции в статических языках расставляются "виртуальные" assert'ы. У тебя вряд ли получится написать код так, что все эти assert'ы собирутся в одном месте
    Вот те же единицы измерения — попробуй переписать свой код так, чтобы все виртуальные assert'ы а-ля assert(typeof(x) == money) собрались в одном месте.

    EP>>В n-ый раз повторю — для неё не имеет смысла. Ведь ты же хочешь сравнить два решения, так?

    EP>>Не вижу смысла сравнивать "кодирование логики на типах" против варианта без этого на задаче где эта самая логика на типах не имеет смысла.
    M>Я тогда совсем плохо начинаю понимать смысл всех этих пафосных заявлений
    Автор: Mamut
    Дата: 07.02.15


    В очередной раз — то что в какой-то твоей конкретной под-задаче, нет смысла кодировать логику на типах, не означает что типы не помогают отловить логические ошибки. Это также не означает что type-rich programming, не помогает отловить больше ошибок чем type-poor programming.

    EP>>Если в этих примерах функция use принимает только конкретный Order<true>, то на этапе компиляции появится ошибка при передачи Order<false>, и в этом случае пользователь функции use будет вынужден отфильтровать типы order'ов, например через pattern matching перегрузкой.

    EP>>Причём всю эту десериализацию из runtime в compile-time можно автоматизировать посредством мета-программирования.
    M>Эээ. Как? (Я просто не знаю)

    Вот пример атомизации конвертации N значений типа bool из runtime в compile-time.
    Здесь read_compile_time_bools считывает заданное количество bool, складывает их в compile-time массив, и после передаёт этот массив в пользовательский функциональный объект (конкретно здесь в лямбду).
    Естественно можно автоматизировать конвертирование и более сложных структур.
    LIVE DEMO
      пример
    #include <boost/mpl/push_back.hpp>
    #include <boost/mpl/for_each.hpp>
    #include <boost/mpl/vector.hpp>
    #include <boost/mpl/bool.hpp>
    #include <boost/mpl/int.hpp>
    #include <boost/mpl/at.hpp>
    
    #include <iostream>
    #include <cstdlib>
    #include <ctime>
    
    using namespace std;
    using namespace boost;
    
    bool read_runtime_bool()
    {
        return rand() % 2 == 1;
    }
    
    template<typename State=mpl::vector<>, int Count, typename F>
    void read_compile_time_bools(mpl::int_<Count>, F f)
    {
        if(read_runtime_bool() == true)
            read_compile_time_bools<typename mpl::push_back<State, mpl::true_>::type>(mpl::int_<Count-1>{}, f);
        else
            read_compile_time_bools<typename mpl::push_back<State, mpl::false_>::type>(mpl::int_<Count-1>{}, f);
            
    }
    
    template<typename State, typename F>
    void read_compile_time_bools(mpl::int_<0>, F f)
    {
        f(State{});
    }
    
    int main()
    {
        srand(time(0));
    
        read_compile_time_bools(mpl::int_<5>{}, [](auto bools)
        {
            mpl::for_each<decltype(bools)>([](auto flag)
            {
                constexpr bool compile_time_bool = decltype(flag)::value;
                static_assert(compile_time_bool == true || compile_time_bool == false, "");
                cout << compile_time_bool << endl;
            });
        });
    }
    Re: Про типы и логику
    От: GreenTea  
    Дата: 25.02.15 12:32
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    M>Выношу из соседнего обсуждения
    Автор: Mamut
    Дата: 02.02.15
    , так как там много флейма и отсутсвие конструктива.


    M>Мне просто действительно интересно. Многие утверждают, что типы помогают (чуть ли не) во всем, вплоть до того, что «тайпчекер проверяет именно логику».


    Всю ветку не читал. Лично для меня напрашивается решение с применением rule engine типа drools.
    Каждое правило (дальше рул) проверяет одну ошибку. Из рула можно вызвать внешний код которые будет лезть куда-то на внешний сервис, если нужно.
    На вход подается объект заказа и новое значение суммы.
    Плюсы такого подхода:
    + декларативное определение рулов в виде: список условий -> результат
    + по умолчанию ситнтаксис выражений похож на java, но есть возможность для рулов задать свой DSL, так что он будет понятен человеку из бизнеса, и далекого от IT. Хотя это не всегда может быть просто.
    + возможность подключить внешний веб редактор для рулов и менять их хоть даже на лету.
    Минусы:
    — поморочиться придется чуть больше чем написать всю логику в коде.

    Каждый из рулов можно покрыть юнит тестами.
    Отредактировано 25.02.2015 12:42 GreenTea . Предыдущая версия . Еще …
    Отредактировано 25.02.2015 12:33 GreenTea . Предыдущая версия .
    Re: Про типы и логику
    От: alex_public  
    Дата: 03.03.15 10:27
    Оценка: 21 (1)
    Здравствуйте, Mamut, Вы писали:

    Эх, что-то я со своим новым проектом так ушёл в дела, что совсем забыл про rsdn. А тут такие забавные вещи обсуждаются... Ну попробую влить новую кровь в затухающую дискуссию. )))

    Значит тебе хочется увидеть пример работы статической типизации в бизнес-логике. Такое встречается не так уж часто и на это есть вполне очевидная причина — подобные проверки в большинстве случаев будут идти не вместо рантайм проверок, а в дополнение к ним (проверяя условия на другом логическом уровне), так что получается увеличение кода без казалось бы существенного увеличения надёжности. Ну а программистская лень общеизвестна... ))) Однако для простенького форумного случая можно и написать демонстрацию. Причём твой "Шаг1" отлично для этого подходит (на следующие шаги естественно это легко экстраполируется, но уже лень). Вот полный компилируемый код примера:

    #include <stdexcept>
    #include <iostream>
    using namespace std;
    
    enum class OrderType {Unknown, OnlyDecrease, Constant};
    template<OrderType Type>
    struct Order{
        const int amount;
        const bool sent;
        const bool risk;
    };
    
    template<OrderType Type> auto RiskOrder(const Order<Type>& o) {return Order<OrderType::Constant>{o.amount, o.sent, true};}
    template<OrderType Type> auto SendOrder(const Order<Type>& o) {return Order<Type==OrderType::Unknown?OrderType::OnlyDecrease:Type>{o.amount, true, o.risk};}
    template<OrderType Type> auto Increase(const Order<Type>& o, int v)
    {
        static_assert(Type==OrderType::Unknown, "You can not increase this order");
        if(o.sent||o.risk) throw invalid_argument("You can not increase this order");
        else return Order<Type>{o.amount+v, o.sent, o.risk};
    }
    template<OrderType Type> auto Decrease(const Order<Type>& o, int v)
    {
        static_assert(Type!=OrderType::Constant, "You can not decrease this order");
        if(Type==OrderType::Unknown&&o.risk) throw invalid_argument("You can not decrease this order");
        else return Order<Type>{o.amount-v, o.sent, o.risk};
    }
    template<OrderType Type, typename F> void ProcessOrder(const Order<Type>& o, F f)
    {
        cout<<"Process order:\t"<<o.amount<<'\t'<<o.sent<<'\t'<<o.risk<<endl;
        try{
            auto r=f(o);
            cout<<"Result order:\t"<<r.amount<<'\t'<<r.sent<<'\t'<<r.risk<<endl;
        }catch(const exception& e) {cout<<e.what()<<endl;}
    }
    
    int main()
    {
        ProcessOrder(Order<OrderType::Unknown>{100, false, false}, [](auto o){//нормально отрабатывает
            auto o1=Increase(o, 10);
            auto o2=SendOrder(o1);
            return Decrease(o2, 20);
        });
        ProcessOrder(Order<OrderType::Unknown>{100, true, false}, [](auto o){//вылетает с исключением в рантайме - плохой входящий ордер для такого алгоритма
            auto o1=Increase(o, 10);
            auto o2=SendOrder(o1);
            return Decrease(o2, 20);
        });
        ProcessOrder(Order<OrderType::Unknown>{100, false, false}, [](auto o){//некомпилируется - компилятор видит ошибку в бизнес логике алгоритма
            auto o1=Decrease(o, 20);
            auto o2=SendOrder(o1);
            return Increase(o2, 10);
        });
    }


    P.S. В случае использования только известных на момент компиляции (т.е. не загружаемых из БД, а скажем создаваемых в коде) order'ов, все рантайм проверки можно полностью выкинуть из кода и тогда данный подход соответственно превращается из "необязательной дополнительной фичи" в наиболее оптимальное решение со всех точек зрения.
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.02.15 19:55
    Оценка: +1
    S>Я видно не понимаю контекста, но зачем тут именно типы?

    Ну, ту просто в соседней теме мне все уши прожужжали, как надо всю логику класть в типы, как это все прекрасно проверится при компиляции и т.п. Вот я не выдержал и свел воедино одну достаточно простую задачу.

    S>Для примитивного опердня за глаза хватит обычных ассертов.


    S>Для чего-то покритичнее нужны контракты + smt-солвер для верификации пост/предусловий + ассерты, чтобы покрыть условия, которые солвер не может вывести автоматически. Или (вариант для бедных), реврайтер чтобы подставлять условия-инварианты в каждый метод + тесты с более-менее полноценным покрытием кода.


    Ой 0_о

    Ну, в целом я на самом деле согласен. У нас, правда, данный конкретный случай решено, по сути, if'ами В change_sum там три функции is_fobidden_1, is_fobidden_2 и is_fobidden_3 где-то на сто строчек После чего происходит собственно увеличение суммы (которое тоже может происходить по-разному из-за всякого разного).

    Хотя да, скажем передвижение заказа по dunning'у у нас описано развесистой машиной состояний, с интересными проверками там и тут и прочими плюшками.

    S>Не, при желании система типов может быть расширена так, чтобы передаваемое значение аннотировалось контрактами метода, этакий adt на стероидах. Но на практике это приведёт к дичайшему гемморою из-за high cohesion: контракты расползаются по всему коду и поменять их ничего не поломав — тот ещё квест.


    Ой. А мне утверждали, что придется меняться не во всем коде, а только в одном месте


    dmitriid.comGitHubLinkedIn
    Re[3]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 15:01
    Оценка: :)
    J>Типы не решают задачу решения задачи в лоб. Они решают задачу бана неправильного кода, где правильность закодирована в определении. У тебя такого бана нету. Можно проверить is_forbidden и тут же дернуть update_amount, и компилятор и не почешется на эту тему, и останется только уповать на тесты.

    Общие фразы ни о чем продолжаются.

    Да можно. Да, не почешется. Только код работает уже много лет и проблем не вызывает. От апологетов типизации слышны только рассказы о том, как типы везде во всем помогут и как все плохо в коде без типов И ни одного внятного примера сложнее, чем hello, world.

    Не говоря уже про смешное
    Автор: jazzer
    Дата: 05.02.15

    Так ведь дело-то в том, что проверку-то ты вставишь, а дальше-то что делать будешь с результатом этой проверки? что в check должно происходить? исключение? ведь надо же как-то наверх сообщить, что облом?




    Что мешает тебе привести пример того, как ты бы решил эту весьма простую задачу так, чтобы и типы были и помогали не дергать ничего в ненужное время?

    Пока что многие говорят, что нет, типы
    Автор: nikov
    Дата: 05.02.15
    тут не помогут
    Автор: Sinix
    Дата: 05.02.15
    никак
    Автор: kaa.python
    Дата: 06.02.15
    , кроме как на самом низком уровне, проверять что мы не складываем километры с килограммами и т.п.



    dmitriid.comGitHubLinkedIn
    Re[4]: Ах да, забыл
    От: jazzer Россия Skype: enerjazzer
    Дата: 06.02.15 18:49
    Оценка: +1
    Здравствуйте, Mamut, Вы писали:

    J>>Не очень понятно, что должно было продемонстрировать твое решение в лоб, кроме того, что задачу можно решить в лоб


    M>Если бы кто-то из апологетов типизации все же решился и показал мастер-класс, можно было бы сравнить, насколько легко переходить из шага 1 в шаг 2, потом в шаг 3 в коде с типами.


    Еще раз — типы вводятся не для легкости, а для корректности.
    Единственное, что облегчают типы — это проверку корректности, потому что ею автоматически занимается компилятор, а не программер с лупой по коду ползает.
    Про то, что их легче писать, никто не говорил (ну, я не говорил; за всех не скажу).

    M>Но пока что никто не рискнул


    Я тоже легко объясню, почему — у меня рабочий день, семья и все такое, я ж не могу только для тебя код писать

    На самом деле, у меня давно уже свой девайс был, еще когда я начал изучать зависимые типы (несколько лет назад, когда тут они активно обсуждались при участии lomeo и thesz) и пытался их сэмулировать на С++ (по сути, тут у нас зависимые типы и проявятся).
    Так что надо посмотреть, в каком виде можно прикрутить мой девайс к твоей формулировке. И заодно перевести его на С++11

    Но я бы хотел посмотреть и на решения на Хаскелле от настоящих сварщиков.
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[3]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 06.02.15 22:16
    Оценка: +1
    Здравствуйте, Mamut, Вы писали:

    M>Ну, ту просто в соседней теме мне все уши прожужжали, как надо всю логику класть в типы,


    Не всю, а как можно больше:

    http://rsdn.ru/forum/philosophy/5942238.1


    M>>Ну и потому что проблемы типов обычно — мизерная часть собственно проблем в коде. У нас в команде вот за год появился первый тикет, который напрямую связан с ошибкой типов. Все остальные проблемы — это логика.
    DM>Ну вот сторонники продвинутых (или хотя бы приличных) систем типов как раз и ратуют за смещение этой границы, чтобы как можно больше логики кодировать в типах и проверять компилятором.

    http://rsdn.ru/forum/philosophy/5942554.1
    Автор: D. Mon
    Дата: 03.02.15

    M>>Действительно, ведь раз логика закодирована типами, она перестает быть логикой, ага, и никогда не может быть неверной.
    DM>Зачем клоуна строишь? Ничего подобного я не говорил и не имел в виду.

    http://rsdn.ru/forum/philosophy/5942643.1
    Автор: Klapaucius
    Дата: 03.02.15

    K>>>Проверки типов.
    M>>Которая поможет мне с логическими ошибками... как?
    K>Так, что некоторые классы ваших логических ошибок будут приводить к ошибкам компиляции.

    http://rsdn.ru/forum/philosophy/5942697.1
    Автор: D. Mon
    Дата: 03.02.15

    DM>Я не говорю, что абсолютно все проблемы выявляются любой системой статических типов. Лишь некоторые. И чем выразительней эта система и чем удачнее применяется, тем больше проблем выявляется при компиляции.

    http://rsdn.ru/forum/philosophy/5943020.1
    Автор: Evgeny.Panasyuk
    Дата: 03.02.15

    EP>Пытаться же запихнуть всю-всю логику в типы — контрпродуктивно, само собой нужен баланс. Как уже неоднократно отмечали выше — типы помогают обнаруживать только некоторые классы ошибок.
    EP>Неплохим примером является кодирование единиц измерения и размерности в тип. Например Mars Climate Orbiter распался в атмосфере Марса из-за того, что разные модули по ошибке использовали разные единицы измерения.


    M>как это все прекрасно проверится при компиляции и т.п.


    Предусловие требующее нахождение параметра функции в одном из состояний из небольшого множества — действительно можно задать в системе типов, причём таким образом что вызывающая сторона не сможет это требование проигнорировать, и в той теме приводили примеры.

    M>Вот я не выдержал и свел воедино одну достаточно простую задачу.


    Ты же понимаешь что из истинности утверждения "логику моего опердня не имеет смысл кодировать в типах", не следует ложность утверждения "при грамотном использовании системы типов, некоторые классы логических ошибок будут приводить к ошибкам компиляции"
    Мол, "шах и мат атеистыстатическая типизация!"
    Re[6]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 06:19
    Оценка: :)
    M>>Которые тут же сыпались при простейших вопросах типа «что будет, если ввести хоть одно доп. условие?».

    EP>Простой пример нескольких условий
    Автор: Evgeny.Panasyuk
    Дата: 05.02.15
    .



    Пример моментально развалился при простейшем вопросе: у нас этих условий не 2, а 12. Будешь делать order_processed_and_prepaid_and_not_risk_and_amount_raise_allowed_and... ?

    EP>Скорее ты не хочешь слышать и видеть.


    Я все вижу и слышу. Вас почему-то корежит от вопросов

    M>>кроме сказок о том, как все с типами будет круто, и «нужно как можно больше логики кодировать на типах».

    EP>Не "всё будет круто", а "целые классы ошибок будут ловиться в compile-time".

    Я привел простейший пример. Покажи мне, как в нем булет отлавливаться целый класс ошибок.

    EP>Во-первых, учитывая то что набор типов не фиксирован, а вычисляется на основе "шаблонов", этого не так уж и мало. Например та же размерность физических величин: разделив метры на секунды, мы получим значение нового типа, с размерностью м/c.

    EP>А во-вторых, на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time. Например "первый и второй параметр должны иметь одинаковый тип", хотя и не говорится какой; или например целая цепочка условий, а-ля ДНФ.

    Имя сестра, имя Примеры, брат, примеры. Я про это и говорю: сплошные сказки про белого бычка. Я привел пример простейшей задачи, которая — ой, ты не поверишь — имеет цепочку условий. Где на практике твое крутое решение, вычисляющее на основе шаблонов и т.п.

    Ах да, я забыл. «Это простой опердень, мне не нравится»


    EP>Почему это не нравится? Задача как задача


    Так где же решение, которое бы показало все твои истории про типы?

    M>>Приведите другую задачу. Но только без hello word'ов, а такую, хоть как-то приближенную к реальности.


    EP>Например CAD модели заданные в аффинном пространстве. Если и точки и вектора имеют тип vector, то возможно допустить логические ошибки: попытаться просуммировать точки; или например передать результат суммы векторов туда, где по логике ожидается точка; или же сохранить сумму точки и вектора в вектор.



    Короче, понятно. Все сказки про «целые классы ошибок» и «цепочки условий» и «логику» на практике упираются ровно в одно: как бы не сложить метры с киллограммами. Этот «целый класс ошибок» является очень маленьким классом ошибок.


    dmitriid.comGitHubLinkedIn
    Отредактировано 07.02.2015 8:33 Mamut [ищите в других сетях] . Предыдущая версия .
    Re[7]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 06:30
    Оценка: :)
    J>И стопятьсот сообщений от тебя про белого бычка, тупо игнорирующих все, что тебе говорят (и это сообщение — тоже яркий тому пример: ты тупо проигнорировал мои слова наверху, и так почти со всем).

    Проигнорорвал какие слова? Давай я приведу твои слова. Ну, например:

    Вот тут как раз и поможет компилятор — как раз с ad-hoc изменениями требований.


    Ой, или например твое долгое недоумение
    Автор: jazzer
    Дата: 05.02.15
    про то, как ошибки возвращать. Что-то там про пачки функций
    Автор: jazzer
    Дата: 06.02.15
    .

    Ну или выше по ветке

    типы вводятся не для легкости, а для корректности.


    J>И потом тебе еще хватает уж не знаю чего заявлять "там много флейма и отсутсвие конструктива".

    J>В зеркало посмотрись сначала.

    Смотрюсь. Каждое утро. И вижу, что от тебя, например, ноль ральных примеров, одни только заявления. Вот, пожалуйста, задача с ad-hoc требованиями. Очень маленькая, на самом деле. Можно увидеть пример того, как (все строго на основе твоих заявлений)

    — компилятор помогает с ad-hoc изменениями
    — типы помогают возвращать ошибки
    — типы помогают проверить корректность

    Ну вот без заявлений о том, как все это прекрасно происходит в теории. А вот на реальной задаче, которой, заметь, занимается банк. Ты ведь презентацию из банка про хаскель привел. Ну вот тебе вполне банковская задача

    Пока что вот результат
    Автор: Слава
    Дата: 07.02.15
    .


    dmitriid.comGitHubLinkedIn
    Re[8]: Ах да, забыл
    От: jazzer Россия Skype: enerjazzer
    Дата: 08.02.15 04:08
    Оценка: +1
    Здравствуйте, Mamut, Вы писали:

    J>>И стопятьсот сообщений от тебя про белого бычка, тупо игнорирующих все, что тебе говорят (и это сообщение — тоже яркий тому пример: ты тупо проигнорировал мои слова наверху, и так почти со всем).


    M>Проигнорорвал какие слова? Давай я приведу твои слова.


    Ну и в очередной раз ты просто процитировал мои слова без какого-либо конструктивного ответа на них. Спасибо за еще одну иллюстрацию.

    Зато еще пару раз повторил
    Автор: Mamut
    Дата: 07.02.15
    , что можешь написать решение в лоб за пять минут, будто кто-то здесь этого не может, и будто кто-то утверждал, что типы позволят писать решение за четыре минуты.

    В общем, классические приемы демагогии в полный рост, можно прямо в учебник вставлять. Особенно виртуозно тебе удаются подмена тезиса и ингорирование аргументов, аплодисменты.
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re: Про типы и логику
    От: Abyx Россия  
    Дата: 08.02.15 10:41
    Оценка: +1
    Здравствуйте, Mamut, Вы писали:

    M>Мне просто действительно интересно. Многие утверждают, что типы помогают (чуть ли не) во всем, вплоть до того, что «тайпчекер проверяет именно логику».


    M>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить.


    Ты бы еще предложил задачу "посчитать md5" и спросил как ее решить "типами".

    Твоя задача сводится к написанию предиката
    state_allows_increment(state) &&
    risk_check_allows_increment() &&
    config_allows_increment(config, amount, delta) &&
    (!shop_policy_applies(state) || shop_policy_allows_increment()) &&
    (!bank_nonshipped_policy_applies(state) || bank_allows_nonshipped_increment() &&
    (!bank_shipped_policy_applies(state) || bank_allows_shipped_increment(delta) && bank_capture(amount + delta))

    это чистая математика (логика), тут даже алгоритма как такового нет, просто длинное булево выражение.
    In Zen We Trust
    Re[9]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 08.02.15 16:29
    Оценка: :)
    J>В общем, классические приемы демагогии в полный рост, можно прямо в учебник вставлять.

    С твоей стороны? Безусловно. Я так и не увидел ни одного мало-мальски внятного примера на хоть одно из твоих заявлений. А ты утверждаешь, что я неконструктивен. Ну-ну.


    dmitriid.comGitHubLinkedIn
    Re[21]: Про типы и логику
    От: WolfHound  
    Дата: 11.02.15 14:39
    Оценка: +1
    Здравствуйте, Mamut, Вы писали:

    M>Причем ты моментально вводишь вводишь два условия:

    M>- Нормальные люди не забывают проверять версию протокола при соединении.
    Это первое что делают адекватные разработчики при создании нового протокола.
    Если разработчики не адекватны, то им не поможет ни какой инструмент.

    M>- При обновлении кода клиента компилятор будет бить по рукам везде.

    Это и есть статическая типизация протокола.
    Если этого нет, то нет и статической типизации.

    M>Пример первый

    Неадекватность разработчиков.
    Инструментами не решается.

    M>Пример второй


    M>Так как у нас нет никакого контроля над клиентским кодом, то клиенты будут присылать все, что им в голову взбредет, потому что никто не защищен от «ненормальных разработчиков», кривых рук да и банальной реализации (абсолютно математически выверенной и статически типизированной, и скомпилированной) типа «отсылаем заголовок Content-Type одной версии, а тело запроса — другой».

    Если код реализующий посылку сообщений генерируется из схемы, в которой прописаны все типы и номер версии, то такого быть не может.
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[24]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 11.02.15 16:11
    Оценка: -1
    WH>Я говорю всего про два:
    WH>1)Программисты должны быть адекватны. Иначе в любом случае всё будет плохо.
    WH>2)Статическая типизация должна быть.

    И в случае с распределенными сервисами: клиенты должны быть обновлены одновременно с сервером (возможно, подпункт первого условия).

    «Адвекватность» программистов измеряется чем? Могу только повторить. Абсолютно адекватный, полностью статически проверенный код:

    to_json :: Object -> string


    И не прикопаешься, все условия выполнены

    WH> Жаловаться на то, что статическая типизация не работает, если её нет весьма странно.


    В первом случае статическая типизация была, она сильно помогла?

    WH> Твой второй пример именно про случай, когда её нет.


    Я не вижу, каким образом это «случай, когда ее нет». Ах да, мы упираемся в неизвестные критерии «адекватности программистов», ага


    dmitriid.comGitHubLinkedIn
    Re[16]: Про типы и логику
    От: genre Россия  
    Дата: 12.02.15 09:18
    Оценка: +1
    Здравствуйте, WolfHound, Вы писали:

    WH>>>JSON динамически типизированный.

    WH>>>Если бы протокол был статически типизирован
    G>>А это как вообще?
    WH>Примерно так: http://en.wikipedia.org/wiki/Interface_description_language

    И какое же отношение это имеет к статической типизации(там json кстати в списке есть, см выше)? Ты говоришь про статическую типизацию реализации протокола, но чем она поможет если клиент на с++, а сервер на, например, java, непонятно
    ... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 04.03.15 16:12
    Оценка: -1
    M>>Ну, начинается Вот не вижу я, чтобы он «естественно легко экстраполируется»

    _>грубо говоря твой "код в лоб" будет переноситься в некую сложную функцию типа CanDecrease, вызываемую в точке if(Type==OrderType::Unknown&&CanDecrease()) throw ... функции Decrease).


    _>Ты действительно видишь здесь что-то сложное? )


    Так. Мой код будет перерастать во что-то сложное, а твой не будет? Можно это продемонстрировать? Да, я лично не вижу, как это экстраполируется


    M>>Ну а по коду видно, что проверок стало в два раза больше, а простор для ошибок — точно такой же, как и без них


    _>Ну для начала статическая типизация не устраняет сами ошибки, а переводит их возникновение из времени исполнения во время компиляции. Что мы и видим в моём примере. Естественно переводятся во время компиляции только те проверки, для которых достаточно знаний на момент компиляции.


    Ну, я имею в виду, что в твоем примере все равно все упирается в то, расставил ли кто-нибудь static_assert'ы по коду. Если по коду есть хотя бы минимальное тестирование (а логику проверять надо), то их полезность по сравнению с динамической типизацией падает экспоненциально. И как показывает твой пример, нам все равно надо отлавливать рантайм-ошибки в зависимости от того, как эти ассерты расставлены. В итоге ответсвенность за логику размыта и стало сложнее проследить, а не забыли ли мы что-либо и правильно ли мы реализовали логику.

    _>Что касается количества проверок... Ты про что, про размер исходника или про нагрузку процессора в рантайме? )


    Нет. Я имел в виду, что вижу по два if'а (грубо говоря) на каждую функцию

    _>>>P.S. В случае использования только известных на момент компиляции (т.е. не загружаемых из БД, а скажем создаваемых в коде) order'ов, все рантайм проверки можно полностью выкинуть из кода и тогда данный подход соответственно превращается из "необязательной дополнительной фичи" в наиболее оптимальное решение со всех точек зрения.

    M>>За пределами теоретических изысканий таких Order'ов в природе не существует

    _>Вообще то как раз существует и даже прямо в твоём случае. Например при создание нового ордера мы можем точно указать его тип и т.д.


    Теоретики такие теоретики. Новый заказ создается из 100% рантайм-данных. И, соотвественно, наделяется всеми свойствами исключительно в рантайме.

    _>P.S. Да, а вообще вся эта ваша архитектура выглядит вообще очень сомнительно и криво. Т.к. по нормальному надо не отлавливать запрещённые пользователю действия и выводить сообщение об ошибке, а просто не позволять их пользователю инициировать. _>Т.е. должна быть функция типа CanIncrease(order), которая вызывается из интерфейса пользователя и соответственно ему не отображается никаких кнопок, которые могут инициировать Increase.


    Боже, какие вы все теоретики. /o\ Кнопочки. В GUI. Не выводить. О чем вы все?

    У меня может прийти 15 000 автоматических запросов на изменение суммы заказа. Просто потому что магазин так решил. Мы должны вернуть этому магазину внятные сообщения, что «нет, дядя, для таких-то и таких-то заказов это нельзя потому что
    Автор: Mamut
    Дата: 06.02.15
    ».

    А пропоненты стат. типизации пока не осилили даже не то, что по ссылке, а простую задачу с тремя-четырьмя условиями Несмотря на все пафосные заявления. Все заканчивается после двух условий и заявления «ну, дальше все понятно/очевидно/экстраполируется»


    dmitriid.comGitHubLinkedIn
    Re[18]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 09.03.15 20:44
    Оценка: -1
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    I>>А что тебя смущает ?


    EP>То что примеры итерации или точек времени очевидны.


    Да, когда нечего сказать, в ход идет аргумент "тут всё просто", "это очевидно"

    EP>>>Да, да, я всё помню, ты сначала пел про то что в одиночку перекодил 40 программистов на задачах линейной алгебры, а потом конечно же подтвердил это

    I>>Вообще говоря ты привел свои догадки пополам с вымыслом. Нет и не было задачи `перекодить` 40 человек.

    EP>Тем не менее, ты зачем-то этим хвастался


    Хвастался, только совсем другим. `перекодить` — боюсь даже представить, что ты себе надумал.

    I>>Покажи внятный пример использования.


    EP>
    EP>auto start = system_clock::now();
    EP>


    Итого — примера нет.

    I>>Профит есть и у векторного пространства. Твоя задача — показать область, где у афинного профит над векторным.

    I>>Пока что ты смог указать chrono.К твоему сведению это не предметная область, а либа.
    I>>Чисто логика — косточка от арбуза не является арбузом. Более того, арбуз имеет смысл есть без косточек

    EP>Я был убеждён в том, что предметная область применения библиотеки std::chrono очевидна


    Попробуй выразить эту очевидность в терминах пользователя, сразу станет ясно. Вот скажем, редактор векторной графики — здесь всё предельно понятно. Попробуй придумать такой же пример, только что бы демонстрировал профит от chrono и сформулируй, почему именно от chrono будет максимум профита.
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.02.15 19:45
    Оценка:
    N>Высокоуровневую логику на типах писать сложно и обычно нерентабельно, и это обычно никто не делает.

    Но как же! Мне тут рядом все уши прожужжали, что надо как можно больше логики складывать в типы!

    N>Но вот пример ошибки в твоей задаче, с которой типы могут помочь... Компилятор может проверять, что мы случайно не складываем погонные метры с килограммами, или что мы не ищем значение в килограммах внутри списка, элементы которого являются "количеством ящиков".


    Да. Это, безусловно, подспорье. Но на практике (80% кода в логике изменения не менялись уже лет пять, остальные 20% менялись этой весной) такое возникает исчезающе редко, особенно если заказ предоставлен черным ящиком, из которого наружу торчат is_processed, is_risk и т.п.

    У нас гораздо больше проблем именно с высокоуровневой логикой.


    dmitriid.comGitHubLinkedIn
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 07:21
    Оценка:
    KP>позволят не писать ряд тестов для проверки корректности поведения с не подходящими типами

    Например?


    dmitriid.comGitHubLinkedIn
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 08:38
    Оценка:
    KP>Мы же явно не хотим что бы foo() падала или как-то еще непортребно себя вела при получении неверного типа в качестве входных данных.

    Аааа. Ну это понятно Но, как я уже говорил, у нас такие ошибки возникают хорошо если раз в год Но тогда да — хочется убивать и системы типов

    Обычно большинство случаев покрывается тестами, которые и так присуствовали бы даже в языке с самой статической из типизаций. Потому что все равно надо написать толпу тестов, проверяющих, что да, мы действительно правильно проверяем все условия и действительно возвращаем нужные ошибки и т.п.


    dmitriid.comGitHubLinkedIn
    Re[2]: Ну и в реальности
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 10:27
    Оценка:
    M>В реальности проверок is_forbidden еще около десятка.

    Условия на запрет изменения

  • если заказ помечен как кредит
  • если заказ помечен как удаленный
  • если заказ помечен как пассивный
  • если заказ помечен как замороженный
  • если заказ помечен как предоплата
  • если заказ помечен как оплаченный по предоплате
  • если в заказе нет товаров, которые можно вернуть

  • если это аггрегированный заказ с прошедшим сроком оплаты
  • если это архивный заказ при условии, что он оплачивается через account
  • если сумма увеличивается, а это запрещено настройками заказа
  • если сумма увеличивается, а мы уже отослали запрос на оплату в банк клиента
  • если сумма увеличивается на сумму большую, чем указано в настройках (относительно оригинальной суммы заказа)

  • если сумма увеличивается, а заказ проведен через новую систему
  • если мы возвращаем деньги клиенту, заказ находится в одном из трех статусов, не является кредитом, и возвращаемая сумма меньше, чем максимальная разрешенная к возврату сумма


  • только после этого будет предпринята попытка изменить сумму заказа. Причем само изменение суммы — это тоже не шубу в трусы заправлять. Это надо сделать запись в бухгалтерию, передвинуть заказ по dunning chain, если надо, сделать нужные записи в кредитной истории, устроить risk check'и, и прочая и прочая.


    dmitriid.comGitHubLinkedIn
    Re[2]: Про типы и логику
    От: Кодт Россия  
    Дата: 06.02.15 12:47
    Оценка:
    Здравствуйте, nikov, Вы писали:

    N>Здравствуйте, Mamut, Вы писали:

    N>Высокоуровневую логику на типах писать сложно и обычно нерентабельно, и это обычно никто не делает. Но вот пример ошибки в твоей задаче, с которой типы могут помочь: представь, что все три флага выше имеют просто тип boolean. Программист может случайно ошибиться, например, в порядке аргументов, и вместо того, чтобы пометить заказ как "предоплачен", пометить его как "отправлен".

    Спасают именованные аргументы вместо позиционных. Структуры с геттерами-сеттерами вместо тупых кортежей.

    N>Если же вместо boolean мы будем использовать три разных типа, с двумя значениями каждый, такую ошибку будет очень трудно совершить случайно. Точно так же, можно использовать разные типы для количества и цены товара, и т.д. Компилятор может проверять, что мы случайно не складываем погонные метры с килограммами, или что мы не ищем значение в килограммах внутри списка, элементы которого являются "количеством ящиков".


    Именованные значения тоже спасают, но тут надо соблюсти баланс между простотой примитивизма (единый bool и вся бесплатная арифметика над ним) и многословием уникальности (надо придумать новые имена, повтыкать всюду код преобразования, тернарные операторы вместо логических и т.п.)

    Именованные аргументы тоже многословны, да ещё и в разных языках может возникать разная нагрузка на рантайм (передача хештаблицы вместо кортежа аргументов — в питоне).
    Перекуём баги на фичи!
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 13:57
    Оценка:
    К>Какой-то небольшой фреймворчик, реализующий аппликативные функторы. В хаскелле, так, всё из коробки будет (я так думаю), а камле, скале и плюсах придётся немножко попотеть.

    Ни у конечно вопрос, надо ли потеть?


    dmitriid.comGitHubLinkedIn
    Re[2]: Ах да, мое решение :)
    От: jazzer Россия Skype: enerjazzer
    Дата: 06.02.15 14:51
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>В общем, решение в лоб. Примерно в таком виде оно существует и у нас, работает, проблем не вызывает.


    Не очень понятно, что должно было продемонстрировать твое решение в лоб, кроме того, что задачу можно решить в лоб
    В этом никто и не сомневался, вообще-то. Можно хоть на бейсике всю твою логику записать.

    Типы не решают задачу решения задачи в лоб. Они решают задачу бана неправильного кода, где правильность закодирована в определении. У тебя такого бана нету. Можно проверить is_forbidden и тут же дернуть update_amount, и компилятор и не почешется на эту тему, и останется только уповать на тесты.
    jazzer (Skype: enerjazzer) Ночная тема для RSDN
    Автор: jazzer
    Дата: 26.11.09

    You will always get what you always got
      If you always do  what you always did
    Re[3]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 15:22
    Оценка:
    J>Не очень понятно, что должно было продемонстрировать твое решение в лоб, кроме того, что задачу можно решить в лоб

    Если бы кто-то из апологетов типизации все же решился и показал мастер-класс, можно было бы сравнить, насколько легко переходить из шага 1 в шаг 2, потом в шаг 3 в коде с типами.

    Именно поэтому:

    Для спортивности: не смотрите в следующий шаг, пока не реализован первый шаг.


    Но пока что никто не рискнул Даже у Кодта наметки
    Автор: Кодт
    Дата: 06.02.15
    , но без продолжения (но он объяснил, почему).


    dmitriid.comGitHubLinkedIn
    Re[4]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 21:56
    Оценка:
    EP>В предыдущей теме, в некоторых местах
    Автор: Mamut
    Дата: 03.02.15
    разговор шёл именно о предварительных проверках, а не внутренних:


    Ты придумал себе какие-то внутренние и внешние проверки В общем, то, о чем я говорил:

    какой-то мегастранный подход апологетов типизации к решению задачи. Почему-то несколько раз для них являлось откровением, что все проверки можно и нужно делать не в местах, откуда вызывается change_amount, а внутри самой функции change_amount.




    EP>

    M>>То есть четвертый пункт — это
    M>>

    M>>if is_activated(Order) and is_auth_only(Order):
    M>>  do_capture(Order)
    M>>

    M>>Еще раз: как именно типы мне помогут?

    EP>В таких случаях пытаться встроить контракт/предусловие в систему типов вполне имеет смысл

    Можно увидеть это не на словах, а на деле?


    dmitriid.comGitHubLinkedIn
    Re[5]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 22:06
    Оценка:
    J>Еще раз — типы вводятся не для легкости, а для корректности.
    J>Единственное, что облегчают типы — это проверку корректности, потому что ею автоматически занимается компилятор, а не программер с лупой по коду ползает.
    J>Про то, что их легче писать, никто не говорил (ну, я не говорил; за всех не скажу).

    Не очень понятно, что должно было продемонстрировать твое решение в лоб, кроме того, что задачу можно решить в лоб
    В этом никто и не сомневался, вообще-то.


    Да, никто не сомневался. Я написал это за 10 минут, на работе. Про типы мне прожужживают уши уже который день и которое сообщение подряд. Но только сказками и рассказами:

    Если ты когда-нибудь собирал мозаичные пазлы, то должен был заметить, что различная форма фрагментов рисунка позволяет избежать большинства ошибок и резко ускорить выполнение задачи. Типы в любой логике выполняют примерно туже самую роль.

    Они решают задачу бана неправильного кода, где правильность закодирована в определении. У тебя такого бана нету. Можно проверить is_forbidden и тут же дернуть update_amount, и компилятор и не почешется на эту тему, и останется только уповать на тесты.

    как можно больше логики кодировать в типах и проверять компилятором. Чем меньше твой язык позволяет выразить типами, тем меньше у тебя ошибок с типами и тем больше ошибок "в логике", это естественно.

    Для типов есть легковесная верификация, в случае их отсутствия не все так радужно. Она не перестает быть логикой, она представляется в форме, которая хорошо подходит для автоматической проверки.

    Поможет тем, что вы можете делать описание чего-то корректным по построению, например. Т.е. сделать нежелательное состояние непредставимым в виде значения.

    Мой пример тривиален, но можно ведь придумать типы и поинтереснее

    Вот тут как раз и поможет компилятор — как раз с ad-hoc изменениями требований.

    А если ты новое требование закодируешь в типе, то за тем, что ты посетил все 1024 места, проследит компилятор, и он просто не скомпилирует твою программу, пока ты не разберешься со всеми 1024 местами, причем пока не разберешься так, что компилятор будет удовлетворен.
    Собственно, в этом весь смысл.
    Типы не делают программирование легче и короче, они делают его надежнее и безопаснее.



    Стопятьсот сообщений о том, как с типами все зашибись. И никто не осилил простейшей задачи, как раз теми самыми ad-hoc требованиями, о которых презентация, на которую ты скинул ссылку.

    Но зато сказок о том, как все прекрасно — ну вот они, выше крыши, в один экран не помещаются.



    Ах, да. IT вообще с какого-то перепугу решил
    Автор: IT
    Дата: 06.02.15
    , что я задачу подгоняю под свою точку зрения. А тут
    Автор: jazzer
    Дата: 06.02.15
    ты на пару с AlexRk рассказываете сказки про то, как все будет хорошо с обработкой заказа на словах, хотя вот она задача, перед глазами. Покажите не сказками про белого бычка, а реальным кодом.

    Это, блин, простейшая бизнес-задача. В которой все ваши рассказы про типы должны просто засиять всеми красками. Где?!


    dmitriid.comGitHubLinkedIn
    Re[5]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 22:15
    Оценка:
    M>>Но пока что никто не рискнул Даже у Кодта наметки
    Автор: Кодт
    Дата: 06.02.15
    , но без продолжения (но он объяснил, почему).


    К>Я начал писать, но понял, что можно сделать красивее, но когда начал переписывать, увидел, что можно ещё красивее сделать... Ну и отвлёкся на поработать.


    Это знакомо


    К>Как видишь, тут и наглядность не страдает, и кастомизабельность — как следствие — достаточно высокая.


    Ээээ, что? Я, конечно, дааавненько на C++ не смотрел, но разобраться во всех этих шаблонах и зависимостях для меня проблема. Скажем, я тут вообще не понимаю: и что же дальше

    По-моему, чтобы такое написать, надо быть семи пядей во лбу

    К>И несложно растащить функции (XXX::work) и метафункции (XXX::precondition, XXX::transform)


    Я за 10 минут растащил все это без шаблонов

    К>Возможно, что в бусте уже всё придумано за нас. А если не придумано, допилю и выложу в продакшен


    Да, хотел бы посмотреть на результат Надо не забывать, из всего этого еще внятные ошибки хотелось бы возвращать


    dmitriid.comGitHubLinkedIn
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.02.15 22:26
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    EP>Здравствуйте, Mamut, Вы писали:


    M>>Ну, ту просто в соседней теме мне все уши прожужжали, как надо всю логику класть в типы,


    EP>Не всю, а как можно больше:


    Спасибо, я эти все сказки свел воедино тут: http://rsdn.ru/forum/philosophy/5946930.1
    Автор: Mamut
    Дата: 07.02.15


    M>>как это все прекрасно проверится при компиляции и т.п.


    EP>Предусловие требующее нахождение параметра функции в одном из состояний из небольшого множества — действительно можно задать в системе типов, причём таким образом что вызывающая сторона не сможет это требование проигнорировать, и в той теме приводили примеры.


    Которые тут же сыпались при простейших вопросах типа «что будет, если ввести хоть одно доп. условие?».

    M>>Вот я не выдержал и свел воедино одну достаточно простую задачу.


    EP>Ты же понимаешь что из истинности утверждения "логику моего опердня не имеет смысл кодировать в типах", не следует ложность утверждения "при грамотном использовании системы типов, некоторые классы логических ошибок будут приводить к ошибкам компиляции"


    Я пока понимаю, что апологеты типов не могут ничего рассказать и показать, кроме сказок о том, как все с типами будет круто, и «нужно как можно больше логики кодировать на типах».

    Любые попытки свести разговор к конкретным примерам заканчиваются лишь очередными сказками или «не, ну оно позволяет не сравнивать километры с килограммами». Это все? Не слишком много для «как можно больше логики кодируй в типах» и прочей «мозаики». Почему-то вся «логика» сводится к «не вызвать функцию F с параметром Y, когда нужен параметр Z»

    Тебе не нравится опердень? Странно. jazzer привел ссылку на презентацию из банка, где опердени — это, по сути, единственное, чем они занимаются. Более того, задача, которую я привел, тоже из банка. Но ни тебе ни IT
    Автор: IT
    Дата: 06.02.15
    эта задача не нравится. Ну что я могу поделать, если ваше чувство прекрасного нарушено этой задачей

    Приведите другую задачу. Но только без hello word'ов, а такую, хоть как-то приближенную к реальности.


    dmitriid.comGitHubLinkedIn
    Re[5]: Ах да, мое решение :)
    От: Evgeny.Panasyuk Россия  
    Дата: 06.02.15 23:04
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    EP>>В предыдущей теме, в некоторых местах
    Автор: Mamut
    Дата: 03.02.15
    разговор шёл именно о предварительных проверках, а не внутренних:

    M>Ты придумал себе какие-то внутренние и внешние проверки В общем, то, о чем я говорил:
    M>

    M>какой-то мегастранный подход апологетов типизации к решению задачи. Почему-то несколько раз для них являлось откровением, что все проверки можно и нужно делать не в местах, откуда вызывается change_amount, а внутри самой функции change_amount.

    M>

    Вот твой изначальный пример:

    http://rsdn.ru/forum/philosophy/5943418.1


    M>
    M>- Есть заказ.
    M>- Пока заказ не помечен, как отправленный, можно уменьшать и увеличивать сумму заказа
    M> ...
    M>

    это можно трактовать как "можно уменьшать и увеличивать сумму заказа" — это функция change_amount, у которой есть предусловие "заказ не помечен как отправленный", которая безусловно изменяет сумму. Тебе как раз и показывали примеры форсирующие это предусловие в compile-time:

    http://rsdn.ru/forum/philosophy/5943812.1


    ARK>
    ARK>  function SendOrder(order: UnsentOrder): SentOrder is
    ARK>    ...
    ARK>  end;
    ARK>  function ChangeOrderSum(order: UnsentOrder, newSum: Money): UnsentOrder is 
    ARK>  // эту функцию нельзя вызвать для заказа, у которого Sent равно true!
    ARK>    ...
    ARK>  end;
    ARK>


    EP>>

    M>>>То есть четвертый пункт — это
    M>>>

    M>>>if is_activated(Order) and is_auth_only(Order):
    M>>>  do_capture(Order)
    M>>>

    M>>>Еще раз: как именно типы мне помогут?

    EP>>В таких случаях пытаться встроить контракт/предусловие в систему типов вполне имеет смысл
    M>Можно увидеть это не на словах, а на деле?

    Конечно:
    template<typename Order>
    enable_if_t<Order::is_activated && Order::is_auth_only> foo(Order order)
    {
        do_capture(order);
    }
    Re[5]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 06.02.15 23:53
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>>>Ну, ту просто в соседней теме мне все уши прожужжали, как надо всю логику класть в типы,

    EP>>Не всю, а как можно больше:
    M>Спасибо, я эти все сказки свел воедино тут: http://rsdn.ru/forum/philosophy/5946930.1
    Автор: Mamut
    Дата: 07.02.15


    И где там говорится что всю логику надо класть в типы?
    "как можно больше" != "всю"

    M>Которые тут же сыпались при простейших вопросах типа «что будет, если ввести хоть одно доп. условие?».


    Простой пример нескольких условий
    Автор: Evgeny.Panasyuk
    Дата: 05.02.15
    .

    M>>>Вот я не выдержал и свел воедино одну достаточно простую задачу.

    EP>>Ты же понимаешь что из истинности утверждения "логику моего опердня не имеет смысл кодировать в типах", не следует ложность утверждения "при грамотном использовании системы типов, некоторые классы логических ошибок будут приводить к ошибкам компиляции"
    M>Я пока понимаю, что апологеты типов не могут ничего рассказать и показать,

    Скорее ты не хочешь слышать и видеть.

    M>кроме сказок о том, как все с типами будет круто, и «нужно как можно больше логики кодировать на типах».


    Не "всё будет круто", а "целые классы ошибок будут ловиться в compile-time".

    M>Любые попытки свести разговор к конкретным примерам заканчиваются лишь очередными сказками или «не, ну оно позволяет не сравнивать километры с килограммами». Это все? Не слишком много для «как можно больше логики кодируй в типах» и прочей «мозаики». Почему-то вся «логика» сводится к «не вызвать функцию F с параметром Y, когда нужен параметр Z»


    Во-первых, учитывая то что набор типов не фиксирован, а вычисляется на основе "шаблонов", этого не так уж и мало. Например та же размерность физических величин: разделив метры на секунды, мы получим значение нового типа, с размерностью м/c.
    А во-вторых, на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time. Например "первый и второй параметр должны иметь одинаковый тип", хотя и не говорится какой; или например целая цепочка условий, а-ля ДНФ.

    M>Тебе не нравится опердень? Странно. jazzer привел ссылку на презентацию из банка, где опердени — это, по сути, единственное, чем они занимаются. Более того, задача, которую я привел, тоже из банка. Но ни тебе ни IT
    Автор: IT
    Дата: 06.02.15
    эта задача не нравится. Ну что я могу поделать, если ваше чувство прекрасного нарушено этой задачей


    Почему это не нравится? Задача как задача

    M>Приведите другую задачу. Но только без hello word'ов, а такую, хоть как-то приближенную к реальности.


    Например CAD модели заданные в аффинном пространстве. Если и точки и вектора имеют тип vector, то возможно допустить логические ошибки: попытаться просуммировать точки; или например передать результат суммы векторов туда, где по логике ожидается точка; или же сохранить сумму точки и вектора в вектор.
    Если же и точки и вектора будут иметь типы Point и Vector соответственно, то подобную логику можно закодировать в сигнатурах операций, и ошибки такого рода будут автоматически находится на этапе компиляции.
    Re[6]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 06:24
    Оценка:
    EP>Вот твой изначальный пример:
    EP>это можно трактовать как "можно уменьшать и увеличивать сумму заказа" — это функция change_amount, у которой есть предусловие "заказ не помечен как отправленный", которая безусловно изменяет сумму. Тебе как раз и показывали примеры форсирующие это предусловие в compile-time:

    Я перенес это «предусловие» внутрь функции change_amount. Что изменилось? Ничего. Все те же «предусловия» надо продолжать проверять прежде, чем произойдет собственно изменение значения. Но почему-то для тебя и остальных апологетов это стало непреодолимым препятствием

    M>>Можно увидеть это не на словах, а на деле?


    EP>Конечно:

    EP>
    EP>template<typename Order>
    EP>enable_if_t<Order::is_activated && Order::is_auth_only> foo(Order order)
    EP>{
    EP>    do_capture(order);
    EP>}
    EP>



    /o\

    Можно увидеть на деле то, что описано в корневом сообщении этого топика? Я за пять минут написал свое решение. Ни один из апологетов типов не осилил написать это решение — только отмазки, рассказы про то, как все будет хорошо, и наугад вырванные отдельные куски условий с заявлениями «видишь, как все хорошо»?



    dmitriid.comGitHubLinkedIn
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 08:29
    Оценка:
    K>С течением времени

    Нет-нет-нет, мы хотим сегодня, нет-нет-нет, мы хотим сейчас


    dmitriid.comGitHubLinkedIn
    Re[7]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 07.02.15 08:53
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Пример моментально развалился при простейшем вопросе: у нас этих условий не 2, а 12. Будешь делать order_processed_and_prepaid_and_not_risk_and_amount_raise_allowed_and... ?


    order<processed, prepaid, not_risk, amount_rise_allowed>, либо просто order<state>

    EP>>Скорее ты не хочешь слышать и видеть.

    M>Я все вижу и слышу. Вас почему-то корежит от вопросов

    От каких?

    M>>>кроме сказок о том, как все с типами будет круто, и «нужно как можно больше логики кодировать на типах».

    EP>>Не "всё будет круто", а "целые классы ошибок будут ловиться в compile-time".
    M>Я привел простейший пример. Покажи мне, как в нем булет отлавливаться целый класс ошибок.

    Например если вместо ордера передадут соединение — целый класс ошибок.
    "Целый класс ошибок" не означает "во всех задачах, большинство ошибок"

    EP>>Во-первых, учитывая то что набор типов не фиксирован, а вычисляется на основе "шаблонов", этого не так уж и мало. Например та же размерность физических величин: разделив метры на секунды, мы получим значение нового типа, с размерностью м/c.

    EP>>А во-вторых, на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time. Например "первый и второй параметр должны иметь одинаковый тип", хотя и не говорится какой; или например целая цепочка условий, а-ля ДНФ.
    M>Имя сестра, имя Примеры, брат, примеры. Я про это и говорю: сплошные сказки про белого бычка. Я привел пример простейшей задачи, которая — ой, ты не поверишь — имеет цепочку условий. Где на практике твое крутое решение, вычисляющее на основе шаблонов и т.п.

    Придётся повторится: "на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time".

    M>Ах да, я забыл. «Это простой опердень, мн ене нравится»


    Где я говорил что мне не нравится?

    EP>>Почему это не нравится? Задача как задача

    M>Так где же решение, которое бы показало все твои истории про типы?

    Какие конкретно "мои истории про типы"?
    Давай уж, приводи цитаты.

    M>Короче, понятно. Все сказки про «целые классы ошибок» и «цепочки условий» и «логику» на практике упираются ровно в одно: как бы не сложить метры с киллограммами. Этот «целый класс ошибок» является очень маленьким классом ошибок.


    Так ты определились, либо "целые классы ошибок" это сказки, либо нет и тебе просто не нравится количество этих классов, а конкретно их концентрация в одном примере из твоего опердня
    Re[7]: Ах да, мое решение :)
    От: Evgeny.Panasyuk Россия  
    Дата: 07.02.15 09:28
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    EP>>Вот твой изначальный пример:

    EP>>это можно трактовать как "можно уменьшать и увеличивать сумму заказа" — это функция change_amount, у которой есть предусловие "заказ не помечен как отправленный", которая безусловно изменяет сумму. Тебе как раз и показывали примеры форсирующие это предусловие в compile-time:
    M>Я перенес это «предусловие» внутрь функции change_amount.

    Нарушение предусловия это баг в программе, программа находится в том состоянии в котором не должна была по логике вещей, и как она туда попала неизвестно, лучше всего пристрелить такую программу как взбесившуюся собаку. Почитай наконец что такое precondition.
    Предусловия можно проверять, и как-то энфорсить, но отнюдь не обязательно. Например assert'ы энфорсящие предусловия часто используют только в отладочных режимах.
    Система типов позволяет энфорсить некоторые предусловия в compile-time, но не все. Я даже больше скажу, далеко не все предусловия можно проверить в runtime — попытка такой проверки попросту может поломать инварианты, и сделать невозможным достижение постусловий.

    M>Что изменилось? Ничего. Все те же «предусловия» надо продолжать проверять прежде, чем произойдет собственно изменение значения.


    Поменялся контракт/интерфейс. Вместо change_amount_unconditionally стало try_change_amount. То что раньше было предусловием, стало обыкновенным перекрёстком в коде. То что раньше было недопустимым состоянием — запуск change_amount с невыполненными условиями — стало штатным режимом работы.

    M>Можно увидеть на деле то, что описано в корневом сообщении этого топика? Я за пять минут написал свое решение. Ни один из апологетов типов не осилил написать это решение


    Я сразу сказал, что в данной постановке это не имеет смысла:

    EP>Если же для запуска функции нет необходимости делать проверки, change_amount сама всё что нужно проверяет внутри, и более того её запуск с невыполненными условиями не является ошибкой, а вполне штатным режимом — то пытаться переписать все эти внутренние проверки на типы, не вижу смысла, это никак не отразится на местах вызова этой функции.


    M>только отмазки, рассказы про то, как все будет хорошо,


    Твои фантазии.

    M>и наугад вырванные отдельные куски условий с заявлениями «видишь, как все хорошо»?


    Это куски из других задач, с другой постановкой. Почему тут приводятся, читай рядом с самими кусками, например:

    EP>В предыдущей теме, в некоторых местах

    разговор шёл именно о предварительных проверках, а не внутренних:

    Re[8]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 09:28
    Оценка:
    EP>order<processed, prepaid, not_risk, amount_rise_allowed>, либо просто order<state>

    Можно увидеть это на примере решения задачи, которую я привел? Ну, на основе твоих заявлений:
    — на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time.
    — как можно больше логики кодировать в типах и проверять компилятором.
    — И чем выразительней эта система [типов] и чем удачнее применяется, тем больше проблем выявляется при компиляции.

    M>>Короче, понятно. Все сказки про «целые классы ошибок» и «цепочки условий» и «логику» на практике упираются ровно в одно: как бы не сложить метры с киллограммами. Этот «целый класс ошибок» является очень маленьким классом ошибок.


    EP>Так ты определились, либо "целые классы ошибок" это сказки, либо нет и тебе просто не нравится количество этих классов, а конкретно их концентрация в одном примере из твоего опердня


    Мне не нравится, что высокопафосные заявления про, например, "на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time." скатываются в банальное «ну, главное чтобы килограммы с метрами не складывались»

    Этот весь «класс ошибок» является весьма маленьким.

    Тебе не нравится пример из опердня, приведи ссылку на код не из опердня


    dmitriid.comGitHubLinkedIn
    Re[10]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 11:05
    Оценка:
    EP>Повторюсь в очередной раз, для этой задачи это не имеет смысла.

    Предложи задачу, для которой имеет


    EP>Да.

    EP>Да, желательно.
    EP>Всё верно.

    Но при этом «для этой задачи не имеет смысла» Причем оно внезапно перестало иметь смысл ровно после того, как все те же множественные условия, о которых ты говорил, остались на месте, только стали не выдуманные тобой вызовы с *-условиями, а стал один вызов

    EP>Вся эта полемика уже сводится к:


    Ложные аналогии такие ложные


    M>>Мне не нравится, что высокопафосные заявления про, например, "на типах можно задать какие угодно условия, главное чтобы аргументы условий были доступны compile-time." скатываются в банальное «ну, главное чтобы килограммы с метрами не складывались»


    EP>Так действительно, при наличии compile-time аргументов их можно использовать в сложных условиях.


    Определи понятие «сложные условия» и почему условия в моей задачи, видимо, недостаточно сложные Или — о ужас — данные о заказе не compile-time, из-за этого ничего поделать нельзя? Ну извини, реальный мир он такой — подавляющее большинство данных получаются не в compile-time

    EP>Например если есть compile-time массив, его можно отсортировать, делать двоичный поиск, и на основании результата разрешать или запрещать вызов конкретной функции. С чем не согласен-то?


    1. Нафига?
    2. Пример того, где это используется, в студию


    M>>Тебе не нравится пример из опердня, приведи ссылку на код не из опердня

    EP>Чем тебе не нравится пример с аффинным пространством? Конкретный пример std::chrono — time_point и duration.
    EP>http://en.cppreference.com/w/cpp/chrono

    Вау. Не прошло и недели и стапятидесяти сообщений, как внезапно кто-то из апологетов родил хоть что-то похожее на реальный пример. Не знаю, при чем тут аффинные пространства, из того, что вижу — это энфорсинг типов. Ну, то самое «не складывать килограммы с метрами». Отлавливается первым же залетным тестом

    Ну да, при рефакотринге будет приятно. В реальных задачах будет занимать мизерную часть проблем.


    dmitriid.comGitHubLinkedIn
    Re[9]: Про типы и логику
    От: DarkEld3r  
    Дата: 07.02.15 13:17
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Этот весь «класс ошибок» является весьма маленьким.

    Правильно я понимаю, что ты за динамическую типизацию вообще? Потому что аргументы уж больно похожи: типы спасают только от сложения яблок с килограммами, а такие ошибки допускают только слабоумные, тесты писать всё равно надо, так что типы не дают ничего.

    По моему, относительно активно за "всю логику на типах" агитировал аж один человек и тот хаскелист, так что не удивительно. Все остальные гораздо осторожнее высказывались. Лично мне на динамических языках писать не особо комфортно, больше нравится когда компилятор помогает. Вот собственно и всё.
    Ну и от языка зависит. Решения на С++ вряд ли будут смотреться сильно изящно, там для простого "strong typedef" надо напрягаться, так что большинство просто на это забивает. В других языках с этим лучше, но так чтобы прямо вся логика на типах и это было удобно и элегантно не видел.

    Имхо, оптимальное решение лежит где-то посредине, а ты пытаешься доказать бесполезность типизации, причём в основном, эмоциями.
    Re[10]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 17:02
    Оценка:
    M>>Этот весь «класс ошибок» является весьма маленьким.
    DE>Правильно я понимаю, что ты за динамическую типизацию вообще?

    Нет. Я готов быть за что угодно, что мне внятно покажут и расскажут.

    DE>Потому что аргументы уж больно похожи: типы спасают только от сложения яблок с килограммами, а такие ошибки допускают только слабоумные, тесты писать всё равно надо, так что типы не дают ничего.


    Мартин Фаулер, например:

    But I discovered that in the presence of SelfTestingCode, most bugs that static types would have were found just as easily by the tests. Since the tests found much more than type errors, you needed them in either a static or dynamically typed language, so having the static typing gave you little gain.


    DE>Имхо, оптимальное решение лежит где-то посредине, а ты пытаешься доказать бесполезность типизации, причём в основном, эмоциями.


    Нет. Я пытаюсь выбить из апологетов типизации хоть что-то реальное, а не последовательные сказки
    Автор: Mamut
    Дата: 07.02.15
    про то, как типизация помогает, спасает, проверят и прочая и прочая и прочая. Любые наводящие вопросы разбиваются о стену новых «верь мне, компилятор все проверит» и т.п. Ну вот ярчайший пример
    Автор: genre
    Дата: 05.02.15
    в соседней ветке.

    Как ты сам знаешь, языком молоть — не мешки таскать. Пока что в двух топиках был намолот вагон и маленькая тележка, но не мешков


    dmitriid.comGitHubLinkedIn
    Re[3]: Про типы и логику
    От: os24ever
    Дата: 07.02.15 18:46
    Оценка:
    M>Нет-нет-нет, мы хотим сегодня, нет-нет-нет, мы хотим сейчас

    Вот это решение
    Автор: artelk
    Дата: 06.02.15
    как раз подойдёт. Добавить в кортеж "Order" признаки "received", "checked", "approved" и так далее — и потребовать, чтобы заказы были допущены к исполнению только в случае, если они были проверены (т.е. у них стоит соответствующий флажок). Проверки сделать через сопоставление с образцом.

    Это не отличается от проверок с помощью типов, но, правда, есть один НЮАНС!
    В ирлонгах отсутствует изменяемое состояние, поэтому ставить флажки не получитьса. Надо будет создавать каждый раз новый кортеж...
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 07.02.15 18:56
    Оценка:
    M>>Нет-нет-нет, мы хотим сегодня, нет-нет-нет, мы хотим сейчас

    O>Вот это решение
    Автор: artelk
    Дата: 06.02.15
    как раз подойдёт. Добавить в кортеж "Order" признаки "received", "checked", "approved" и так далее — и потребовать, чтобы заказы были допущены к исполнению только в случае, если они были проверены (т.е. у них стоит соответствующий флажок). Проверки сделать через сопоставление с образцом.


    Можно код полностью, пожалуйста? А то «добавь тут, добавь там, допущены к исполнению» — это как-то сверх-абстрактно

    O>Это не отличается от проверок с помощью типов, но, правда, есть один НЮАНС!

    O>В ирлонгах отсутствует изменяемое состояние, поэтому ставить флажки не получитьса. Надо будет создавать каждый раз новый кортеж...

    Ээээ чо?


    dmitriid.comGitHubLinkedIn
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 08.02.15 16:28
    Оценка:
    M>>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить.
    A>Ты бы еще предложил задачу "посчитать md5" и спросил как ее решить "типами".

    Как смешно наблюдать, как все сказки
    Автор: Mamut
    Дата: 07.02.15
    сводятся в итоге к «нам не нравится твоя задача» и «тут типами нечего решать»


    A>Твоя задача сводится к написанию предиката


    Не сводится. В частности, если этот предикат не сработает, какую ошибку ты вернешь в вызывающий код?


    A>это чистая математика (логика), тут даже алгоритма как такового нет, просто длинное булево выражение.


    Приведи другой пример


    dmitriid.comGitHubLinkedIn
    Re[6]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 08.02.15 16:31
    Оценка:
    M>>Можно код полностью, пожалуйста? А то «добавь тут, добавь там, допущены к исполнению» — это как-то сверх-абстрактно
    O>Флажки будет проверять функция:
    O>А вызывать её будем так:
    O>По аналогии с операторами в C, переключающими и проверяющими битовые флажки.
    O>Только здесь при добавлении/отключении флажка придётся заново создавать новый кортеж Order.

    А, так стало понятнее По сути, это более наглядно переписанный мой пример. Согласен


    dmitriid.comGitHubLinkedIn
    Re[9]: Ах, да
    От: Mamut Швеция http://dmitriid.com
    Дата: 08.02.15 16:34
    Оценка:
    J> Особенно виртуозно тебе удаются подмена тезиса и ингорирование аргументов, аплодисменты.

    Где ты считаешь, что я подменяю тезисы, и где ты видешь аргументы
    Автор: Mamut
    Дата: 07.02.15
    ?

    Давай, я напомню твой личный аргумент, а?

    Вот тут как раз и поможет компилятор — как раз с ad-hoc изменениями требований.


    Вот появилась задача с ad-hoc требованиям, основанная на реальной задаче из кода самого настоящего банка. Специально написал, чтобы проверить, как все ваши заявления работают при столкновении с реальной задачей.

    Что в ответ? Пшик, тишина


    dmitriid.comGitHubLinkedIn
    Re[2]: Ой, как я мог пропустить
    От: Mamut Швеция http://dmitriid.com
    Дата: 08.02.15 16:37
    Оценка:
    A>это чистая математика (логика), тут даже алгоритма как такового нет, просто длинное булево выражение.

    Если ты когда-нибудь собирал мозаичные пазлы, то должен был заметить, что различная форма фрагментов рисунка позволяет избежать большинства ошибок и резко ускорить выполнение задачи. Типы в любой логике выполняют примерно туже самую роль.

    как можно больше логики кодировать в типах и проверять компилятором.

    Для типов есть легковесная верификация, в случае их отсутствия не все так радужно. Она [логика] не перестает быть логикой, она представляется в форме, которая хорошо подходит для автоматической проверки.


    Аплогеты типов, вы уже определитесь со своим набором рассказов про типы А то вы опровергаете слова друг друга


    dmitriid.comGitHubLinkedIn
    Re[3]: Про типы и логику
    От: Abyx Россия  
    Дата: 08.02.15 21:57
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>>>У меня есть простейшая задача, мне просто интересно, как она будет решаться типами, и/или как типы могут помочь ее решить.

    A>>Ты бы еще предложил задачу "посчитать md5" и спросил как ее решить "типами".

    M>Приведи другой пример


    а что именно ты хочешь? полиморфизм?
    возьми задачу где есть сущности разных типов, например парсер выражений, рисователь картинок, генератор отчетов, — что-то где есть несколько объектов с разным поведением.
    тогда у тебя так или иначе будут разные структуры данных с прибитым к ним кодом.

    или тебе надо статическую проверку типов?
    ну это банальное "T& x; x.y()" vs "T* x; if (x) x->y()" в С++
    или signed vs unsigned,
    или optional<T> и прочие паттерн-матчинги, монады и вот это всё
    In Zen We Trust
    Re[11]: Про типы и логику
    От: enji  
    Дата: 09.02.15 05:59
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>

    M>But I discovered that in the presence of SelfTestingCode, most bugs that static types would have were found just as easily by the tests. Since the tests found much more than type errors, you needed them in either a static or dynamically typed language, so having the static typing gave you little gain.


    Это все мило, вот только количество тестов разное. У тебя везде 100% покрытие тестами, причем не по строкам, а по логике? Если так — ты крут. Однако не всегда есть возможность так делать. И если мы на статически типизированном языке, часть ошибок выловит компилятор. Зачем от этого отказываться?

    M>Нет. Я пытаюсь выбить из апологетов типизации хоть что-то реальное, а не последовательные сказки
    Автор: Mamut
    Дата: 07.02.15
    про то, как типизация помогает, спасает, проверят и прочая и прочая и прочая. Любые наводящие вопросы разбиваются о стену новых «верь мне, компилятор все проверит» и т.п. Ну вот ярчайший пример
    Автор: genre
    Дата: 05.02.15
    в соседней ветке.


    Ты ставишь вопрос — как реализовать всю логику на типах. Тебе отвечают — типы не позволяют сложить километры с килограммами, вызвать отсутствующую функцию, позвать функцию с неверным количеством аргументов. Чего ты еще хочешь то?
    Re[10]: Ах, да
    От: enji  
    Дата: 09.02.15 06:05
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Вот появилась задача с ad-hoc требованиям, основанная на реальной задаче из кода самого настоящего банка. Специально написал, чтобы проверить, как все ваши заявления работают при столкновении с реальной задачей.


    Типы помогут, когда ты при изменении требований вдруг куда-нибудь передашь строку вместо числа или вызовешь функцию, в которой поменялось количество аргументов. И у тебя не будет юнит-теста, который при этом свалится. Но врядли ты с их помощью проверишь бизнес-логику, если конечно предварительно сильно не заморочиться, в духе того, что предлагал Кодт выше. Однако так врядли кто-то делает
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 08:20
    Оценка:
    IT>Ты пытаешься сделать тоже самое. Показать на примитивной задаче ненужность типов. При этом делая акцент не на примитивности, а на ненужности.

    Нет, не пытаюсь. Я пытаюсь выбить из апологетов типов что-то большее, чем тонны текста про то, как с типами все хорошо. Не нравится эта задача — предложи/покажи другую задача. В чем проблема-то?

    Ведь jazzer же привел презентацию из банка, в которой утверждалось, что, мол, «типы не позволяют писать неправильный код», например. Я привел реальную задачу из банка Нет, задача не такая, я оказывается что-то доказать хочу и прочая и прочая.

    Могу только повторить

    Вот я не понимаю. Спрашиваешь вопрос про любой язык программирования — тебе и ответят, и примеры покажут, и ссылки подкинут — все, что угодно. Как только дело доходит до апологетов «типы везде, они рулят», все, тишина, одна демагогия на пять страниц ответов


    Вот тут несколько человек в хором говорят
    Автор: Mamut
    Дата: 07.02.15
    о разных преимуществах типов. Что мешает привести ну хоть мало-мальский пример типа задачи, что я привел?

    Ну, показать, мол: вот у нас есть такие требования, мы их решили так и так. Потом требования поменялись, мы меняем так, а нам типы помогат это сделать вот эдак. Ну вот продемонстрировать все эти «картинки», «паззлы», «компилятор помогает с ad-hoc требованиями», «типы помгают реализовывать сложные условия» и прочая и прочая?


    [тонны текста про картинки и паззлы скипнуты]

    IT>Типы — это дополнительный уровень верификации кода на самых ранних этапах возникновения проблемы. Те же юнит-тесты ловят последствия, типы позволяют устранить причину. Мне вообще странно слышать подобные разговоры от людей с опытом. То, что вы у себя в конторе научились есть кактус и при этом не сильно колоться, говорит лишь о вашем упёрстве и пониженном болевом пороге. Это очень круто. Примерно так же круто, как в цирке глотать шпаги или совать голову в пасть хищнику. И если бы вы со своим кактусом выступали в цирке, то я бы аплодировал стоя. Но в жизни то это нафига нужно?


    Опять — тонны текста, демагогия, аналогии и рассказы о том, каким мы тупые, с нашим кактусом. Извини. Это — не аргументация.


    dmitriid.comGitHubLinkedIn
    Re[11]: Ах, да
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 08:22
    Оценка:
    E>Типы помогут, когда ты при изменении требований вдруг куда-нибудь передашь строку вместо числа или вызовешь функцию, в которой поменялось количество аргументов. И у тебя не будет юнит-теста, который при этом свалится.

    С этим я и не спорю: http://rsdn.ru/forum/philosophy/5946038.1
    Автор: Mamut
    Дата: 06.02.15


    E>Но врядли ты с их помощью проверишь бизнес-логику, если конечно предварительно сильно не заморочиться, в духе того, что предлагал Кодт выше. Однако так врядли кто-то делает


    И все? Это, имхо, идет сильно вразез с тем, что мне тут в сотне сообщений рассказывали


    dmitriid.comGitHubLinkedIn
    Re[12]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 08:25
    Оценка:
    E>Это все мило, вот только количество тестов разное. У тебя везде 100% покрытие тестами, причем не по строкам, а по логике? Если так — ты крут. Однако не всегда есть возможность так делать. И если мы на статически типизированном языке, часть ошибок выловит компилятор. Зачем от этого отказываться?

    Количество тестов далеко не 100%, но при этом проблемы, связанные именно со «складыванием килограммов с километрами» вылезают очень и очень редко. Самые главные проблемы — это именно бизнес-логика.

    M>>Нет. Я пытаюсь выбить из апологетов типизации хоть что-то реальное, а не последовательные сказки
    Автор: Mamut
    Дата: 07.02.15
    про то, как типизация помогает, спасает, проверят и прочая и прочая и прочая. Любые наводящие вопросы разбиваются о стену новых «верь мне, компилятор все проверит» и т.п. Ну вот ярчайший пример
    Автор: genre
    Дата: 05.02.15
    в соседней ветке.


    E>Ты ставишь вопрос — как реализовать всю логику на типах. Тебе отвечают — типы не позволяют сложить километры с килограммами, вызвать отсутствующую функцию, позвать функцию с неверным количеством аргументов. Чего ты еще хочешь то?



    Эээ нет. Мне отвечают в стиле «как можно логики переносить в типы» и «решают задачу бана неправильного кода, где правильность закодирована в определении. У тебя такого бана нету. Можно проверить is_forbidden и тут же дернуть update_amount, и компилятор и не почешется на эту тему, и останется только уповать на тесты» и прочие «паззлы».

    Как только просишь привести конкретные примеры — в ответ тишина.

    Если все сводится только к «типы не позволяют сложить километры с килограммами», то так и говорите Я проти этого вообще и слова не скажу


    dmitriid.comGitHubLinkedIn
    Re[12]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 08:47
    Оценка:
    EP>>>Повторюсь в очередной раз, для этой задачи это не имеет смысла.
    M>>Предложи задачу, для которой имеет

    EP>Для тех задач где есть какие-то предусловия:


    В первом же сообщении этой темы есть задача, где эти предусловия есть. То есть до того, как мы собственно меняем amount, у нас идет толпа предусловий


    EP>
    EP>template<typename State>
    EP>enable_if_t
    EP><
    EP>    State::prepared && State::risk_checked || State::approved_by_boss
    >> change_amount_unconditionally(Order<State> x, Money amount)
    EP>{
    EP>    // ...
    EP>}
    EP>



    Можно мне наконец увидеть полное решение задачи в корневом сообщении со всеми этими enable_if_t?

    M>>Определи понятие «сложные условия» и почему условия в моей задачи, видимо, недостаточно сложные


    EP>Runtime данные можно переводить в compile-time, причём данные любой сложности, об этом я неоднократно говорил в предыдущем топике, и даже приводил конкретный код. Вопрос упирается в code-bloat.


    Можно ссылку на конкретный код? Потому что я помню только куски кода, которые разваливались от банального вопроса типа «а что будет, если у нас немного больше условий, чем проверка на одно состояние».

    EP>Перевести несколько bool из runtime в compile-time — не проблема. А вот например перевод unsigned price — скорей всего будет непрактичным.


    Можно увидеть это на примере задачи з корневого сообщения?

    EP>Более сложный пример: на типах можно задать грамматику DSL, и разрешать только те выражения, которые проходят проверку. Пример — Boost.Proto.


    Спасибо. Наконец-то, часть вторая

    Да, про DSL'и я согласен. Хотя и тут есть свои «но» (опишу отдельным текстом в конце этого сообщения)

    M>>Отлавливается первым же залетным тестом

    EP>Mars Climate Orbiter тесты не спасли. Хотя, по всей видимости, тестировалось всё более пристрастно чем типичный опердень.
    EP>Image: mars98orb.jpg

    В зависимости от реализации, типы тоже могут нифига не спасти

    Классический пример, у нас был, кстати. Идет общение со сторонним сервисом. Мы отдаем JSON, та сторона принимает JSON. Наша сторона банально пакует данные в JSON и отправляет. На той стороне JSON принимается, распаковывается и используется.

    Ну, с нашей стороны приходит валидный объект, генерируется валидный JSON, но в какой-то момент все ломается Принимающая сторона решила, что теперь поле X должно быть не числом, а строкой

    M>>Ну да, при рефакотринге будет приятно. В реальных задачах будет занимать мизерную часть проблем.


    EP>И даже 100% покрытие строчек кода тестами не даёт гарантии что все ошибки этого класса найдены.


    100% покрытие типами вообще не дает никакой гарантии, что код вообще правильный Могу только повторить. У нас самые главные проблемы — это бизнес-логика, а не несоответсвие килограммов с километрами

    ------

    Про DSL. Ну, может не столько про DSL, но все же.

    Банки общаются между собой так называемыми payment files. Это, по сути, — текстовые файлы с определенной структурой, где каждая строка (грубо говоря) — это указание кто кому сколько денег перевел на какой тип счета. По большому счету — это примитивный DSL, потому что там есть какие-то управляющие конструкции и контекстно зависимые поля, емнип.

    На все это дело есть полтора международных стандарта, которым банки должны следовать.

    АГАЩАЗБЛИН

    У каждого первого банка есть свои мысли по поводу того, как реализовывать эти стандарты (благо там есть двусмысленные места), и каждые первые же расширяет эти стандарты своими нестандартными расширениями

    Вот пишет команда весь их себя правильный парсер, не позволяющий никаких неправильных конструкций и при первом же прогоне на реальных файлах получает всякие TypeError'ы, потому что ожидалось целое, а пришел float и т.п. И все в рантайме

    Но сам парсер правильный, да

    В общем, интеграция каждого нового банка занимает почти неделю. Одна из причин — попытка выяснить, в каких именно местах они отходят от стандарта, и каким образом они его расширяют. А потом минимум раз в месяц банк присылает файл, который не соответсвует ни стандарту ни тому, что они рассказали про свои файлы catch TypeError -> log("банк снова офигел, см. файл такой-то")

    В общем, этот рассказ не столько против типов, сколько про то, что типы наверняка помогут сделать правильный DSL. Но потом в этот DSL начинает приходить все, что угодно, и вылетать оно будет, как назло, в рантайме


    dmitriid.comGitHubLinkedIn
    Re[4]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 08:55
    Оценка:
    M>>Приведи другой пример
    A>а что именно ты хочешь? полиморфизм?


    Я хочу, чтобы мне пошагово, на примерах (желательно, приближенных к реальным задачам) показали хоть что-то из этих рассказов
    Автор: Mamut
    Дата: 07.02.15
    .

    Я многого прошу? Да вроде нет. Тут в соседних
    Автор: x-code
    Дата: 12.01.15
    темах
    Автор: x-code
    Дата: 21.01.15
    ни у кого нет никаких
    Автор: AlexRK
    Дата: 26.10.14
    проблем
    Автор: NeoCode
    Дата: 10.12.14
    продемонстрировать
    Автор: _NN_
    Дата: 02.12.14
    что-либо
    Автор: vsb
    Дата: 04.11.14
    на примерах
    Автор: x-code
    Дата: 26.10.14
    . Доходит вопрос до статической типизации — тонны текста, ноль примеров.

    A>или optional<T> и прочие паттерн-матчинги, монады и вот это всё


    Да-да-да, вот это всё ©


    dmitriid.comGitHubLinkedIn
    Re[7]: Ах да, забыл
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 10:20
    Оценка:
    К>Дальше получается так

    Ага. Все, понял.

    Ну и да, без auto это действительно могла выглядеть страшно и многословно

    К>Так, небось, всё в рантайме сделал на эрланге. В рантайме-то любой дурак сделает.


    Ну дык


    dmitriid.comGitHubLinkedIn
    Re[13]: Про типы и логику
    От: WolfHound  
    Дата: 09.02.15 15:26
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Классический пример, у нас был, кстати. Идет общение со сторонним сервисом. Мы отдаем JSON, та сторона принимает JSON. Наша сторона банально пакует данные в JSON и отправляет. На той стороне JSON принимается, распаковывается и используется.

    JSON динамически типизированный. Из-за этого все те проблемы, о которых ты тут плачешь.

    Если бы протокол был статически типизирован и компилятор бил бы по рукам разработчиков, которые пытаются сделать что-то не так, то данного класса проблем бы не было.
    О чем тебе и говорят.

    Но ты продолжаешь твердить, что типы не нужны.
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[14]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 09.02.15 15:44
    Оценка:
    WH>JSON динамически типизированный. Из-за этого все те проблемы, о которых ты тут плачешь.

    Я не плачу про проблемы.

    WH>Если бы протокол был статически типизирован и компилятор бил бы по рукам разработчиков, которые пытаются сделать что-то не так, то данного класса проблем бы не было.


    Если бы да кабы, да во рту росли грибы. «Статически типизированный протокол» может быть хоть четырежды статически типизированным, но это не спасет от банальнейшей ситуации:

    Сервер. Начинает принимать протокол версии 2.0, который меняет тип поля.
    Клиент. Продолжает отсылать протокол версии 1.2, в котором тип поля старый.

    WH>О чем тебе и говорят.

    WH>Но ты продолжаешь твердить, что типы не нужны.

    Я не твержу, что типы не нужны.


    dmitriid.comGitHubLinkedIn
    Re[6]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 10.02.15 09:12
    Оценка:
    IT>Выбивают обычно показания, причём желательно устраивающие выбивающего. Впрочем, именно этим ты тут и занимаешься. Тебя же ведь не интересует истина, правда? Тебе же нужно по любому отстоять своё мнение.


    Нет. Мне не надо отстоять свое мнение. Свое мнение я высказывал несколько раз:

    M>>Опять — тонны текста, демагогия, аналогии и рассказы о том, каким мы тупые, с нашим кактусом. Извини. Это — не аргументация.


    IT>По поводу типов повторюсь ещё раз. Мне очень странно слыашать подобные разговоры от человека с опытом. Ты споришь с основами мироздания в программировании. С аксиомами. Это даже доказывать не надо. Ты пойми, как параллельные прямые не пересекаются, так и типизация устраняет причины возникновения ошибок, связанных с типами. Ты бы ещё начал доказывать, что если "Hello, world" можно написать в notepad, то всякие вижуал студии и решарперы овно, никому не нужны и даже вредны.


    Тебе в каждом сообщении мерещатся только тонны текста


    Говорит мне человек и продолжает писать тонны текста.


    «типизация устраняет причины возникновения ошибок, связанных с типами» — с этим утверждением я нигде не спорю Я последовательно прошу привести примеры утверждений, которые начинаются от «типы не позволят написать неверный код» до прочих многословных пафосных заявлений
    Автор: Mamut
    Дата: 07.02.15
    .

    Я могу только повторить http://rsdn.ru/forum/philosophy/5948529.1
    Автор: Mamut
    Дата: 09.02.15


    Ты почему-то видишь какие-то «подгонки под мое видение мира» и «тебе не нужна истина»


    dmitriid.comGitHubLinkedIn
    Re[14]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 10.02.15 09:28
    Оценка:
    EP>Вот если бы это изменение amount, с предусловиями, многократно использовалось в разных местах — то какой-то смысл был бы.
    EP>А так получится явно более громоздко чем твой вариант

    Ну то есть типы помогают только при copy-paste based programming'е? Как только одинаковые «предусловия» из ста мест переносятся в один вызов API, они сразу становятся ненужны и «более громоздки»?

    EP>В n-ый раз повторю — для неё не имеет смысла. Ведь ты же хочешь сравнить два решения, так?

    EP>Не вижу смысла сравнивать "кодирование логики на типах" против варианта без этого на задаче где эта самая логика на типах не имеет смысла.

    Я тогда совсем плохо начинаю понимать смысл всех этих пафосных заявлений
    Автор: Mamut
    Дата: 07.02.15


    EP>Если в этих примерах функция use принимает только конкретный Order<true>, то на этапе компиляции появится ошибка при передачи Order<false>, и в этом случае пользователь функции use будет вынужден отфильтровать типы order'ов, например через pattern matching перегрузкой.

    EP>Причём всю эту десериализацию из runtime в compile-time можно автоматизировать посредством мета-программирования.

    Эээ. Как? (Я просто не знаю)


    EP>В таких случаях код сериализации нужно генерировать из общей схемы, причём желательно включать номер ревизии этой самой схемы в передачу.


    Это да. Но это вопрос не к типизации, а культуре программирования. В нашей команде, несмотря на динамическую типизацию, с этим (ну,с проникновением неправильных типов) проблем нет, потому что для каждого вызова есть описание в виде JSON Schema, с проверками входных и выходных данных на соответствие этой схеме. Плюс все (обратно несовместимые) изменения обязательно меняют номер версии.

    В итоге доходит до смешного. Абсолютно все пользователи нашего API имеют такую же JSON Schema, как и мы (все получают их из одного центрального места). Но потом приходит письмо типа «пацаны, мы вам все присылаем правильно, а оно не работает, посмотрите, в чем ошибка». А ошибка, которую они получают, выглядит типа так:

    HTTP 400 Bad Request
    Content-Type  application/vnd.klarna.com.error-v2+json
    
    {
      "message": "An error has occured. Please try again later",
      "developer_message": "Field order.billing_address.zip must be a string",
      "error_location": "/order/0/billing_address/zip"
    }


    Потому что запрос не прошел валидацию по схеме. Сидишь и думаешь: ну ведь не мы же идиоты, да? А все таки программисты у клиента


    M>>Могу только повторить. У нас самые главные проблемы — это бизнес-логика, а не несоответсвие килограммов с километрами

    EP>Я не знаю что конкретно ты называешь бизнес-логикой, но для меня несоответствие килограммов с километрами это проблема из предметной области.

    Ну бизнес-логикой я называю, например, тот же пример из корневого сообщения.


    M>>В общем, этот рассказ не столько против типов, сколько про то, что типы наверняка помогут сделать правильный DSL. Но потом в этот DSL начинает приходить все, что угодно, и вылетать оно будет, как назло, в рантайме

    EP>Я говорил не просто про DSL, а про Embedded Domain Specific Language, Boost.Proto как раз про это.
    EP>То есть в C++ встраивается под-язык какой-то предметной области. И система типов помогает отлавливать грамматические ошибки в этом самом EDSL на этапе компиляции.

    Ну, в этих случаях это понятно, тут да. Так как все известно и доступно на момент компиляции, то каких-либо возражений против этого не имею


    dmitriid.comGitHubLinkedIn
    Re[15]: Про типы и логику
    От: WolfHound  
    Дата: 10.02.15 13:00
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Если бы да кабы, да во рту росли грибы.

    Аргументов как обычно нет...

    M>Сервер. Начинает принимать протокол версии 2.0, который меняет тип поля.

    M>Клиент. Продолжает отсылать протокол версии 1.2, в котором тип поля старый.
    Спасает. Нормальные люди не забывают проверять версию протокола при соединении.
    И вместо мутных багов будет понятное сообщение о том, что нужно протокол обновить.
    При обновлении кода клиента компилятор будет бить по рукам везде, где программист забудет исправить типы.

    M>Я не твержу, что типы не нужны.

    А чем ты тут занимаешься?
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[16]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 10.02.15 19:56
    Оценка:
    M>>Сервер. Начинает принимать протокол версии 2.0, который меняет тип поля.
    M>>Клиент. Продолжает отсылать протокол версии 1.2, в котором тип поля старый.
    WH>Спасает. Нормальные люди не забывают проверять версию протокола при соединении.

    Спасает при условии нормальных людей

    WH>И вместо мутных багов будет понятное сообщение о том, что нужно протокол обновить.


    Ой. Ты не поверишь, в нашей команде у нас такое прекрасно происходит с вовсю динамическим Эрлангом.

    WH>При обновлении кода клиента компилятор будет бить по рукам везде, где программист забудет исправить типы.


    Ага. При обновлении кода клиента. Ну вот мы обновили код клиента в насквозь динамическом Эрланге, и все заработало на ура.


    Смешно, как ты утверждаешь, что «данного класса проблем бы не было.», но потом тут же повторяешь ровно то, что я говорю: что нифига она не спасает, если
    — Нормальные люди не забывают проверять версию протокола
    — Клиент не обновлен



    M>>Я не твержу, что типы не нужны.

    WH>А чем ты тут занимаешься?

    Я на этот вопрос ответил уже много раз


    dmitriid.comGitHubLinkedIn
    Отредактировано 10.02.2015 20:10 Mamut [ищите в других сетях] . Предыдущая версия .
    Re[17]: Про типы и логику
    От: WolfHound  
    Дата: 10.02.15 20:22
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Ага. При обновлении кода клиента. Ну вот мы обновили код клиента в насквозь динамическом Эрланге, и все заработало на ура.

    В итоге доходит до смешного. Абсолютно все пользователи нашего API имеют такую же JSON Schema, как и мы (все получают их из одного центрального места). Но потом приходит письмо типа «пацаны, мы вам все присылаем правильно, а оно не работает, посмотрите, в чем ошибка». А ошибка, которую они получают, выглядит типа так:

    HTTP 400 Bad Request
    Content-Type  application/vnd.klarna.com.error-v2+json
    
    {
      "message": "An error has occured. Please try again later",
      "developer_message": "Field order.billing_address.zip must be a string",
      "error_location": "/order/0/billing_address/zip"
    }

    (С)
    Автор: Mamut
    Дата: 10.02.15

    Ты в каком из двух сообщений врёшь?

    Если бы схема проверялась статически, то таких ошибок бы не было.
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[18]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 10.02.15 21:53
    Оценка:
    M>>Ага. При обновлении кода клиента. Ну вот мы обновили код клиента в насквозь динамическом Эрланге, и все заработало на ура.

    WH>Ты в каком из двух сообщений врёшь?


    Ни в одном. Ты просто не способен понимать, что твои оппоненты пишут.

    WH>Если бы схема проверялась статически, то таких ошибок бы не было.


    Клиенты нам пишут чем угодно, никаких проблем с проникновением неправильных типов на сервер у нас нет, от слова вообще. Мы клиентам предоставляем только схему. Неправильная реализация этой схемы — целиком на совести клиентов, и от типов не зависит, от слова вообще.

    Более того. Вот это полностью статически типизированная, абсолютно правильная с точки зрения типов реализация:
    to_json :: Object -> string
    to_json(Object) ->
       "выплевываем правильно сформированный JSON."


    dmitriid.comGitHubLinkedIn
    Re[19]: Про типы и логику
    От: WolfHound  
    Дата: 11.02.15 09:44
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Ни в одном. Ты просто не способен понимать, что твои оппоненты пишут.

    В одном сообщении ты говоришь, что всё работает на ура.
    А в другом говоришь, что сыпятся ошибки типов.

    M>Клиенты нам пишут чем угодно, никаких проблем с проникновением неправильных типов на сервер у нас нет, от слова вообще.

    Зато есть проблемы с отправкой. Ибо клиенты не делают статических проверок типов по схеме при генерации JSON.

    M>Мы клиентам предоставляем только схему. Неправильная реализация этой схемы — целиком на совести клиентов, и от типов не зависит, от слова вообще.

    И кто тут не понимает, что ему говорят?
    Если в схеме прописаны типы, то мы можем статически проверить код, который генерирует JSON.

    M>Более того. Вот это полностью статически типизированная, абсолютно правильная с точки зрения типов реализация:

    И в каком месте тут идёт статическая проверка схемы?
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[20]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 11.02.15 14:02
    Оценка:
    M>>Ни в одном. Ты просто не способен понимать, что твои оппоненты пишут.
    WH>В одном сообщении ты говоришь, что всё работает на ура.
    WH>А в другом говоришь, что сыпятся ошибки типов.

    Охохо.

    Давай сначала.

    Ты утверждаешь, что статическая проверка проверит все и все и не позволит допустить ошибок при смене протокола: «Если бы протокол был статически типизирован и компилятор бил бы по рукам разработчиков, которые пытаются сделать что-то не так, то данного класса проблем бы не было.»

    Причем ты моментально вводишь вводишь два условия:
    — Нормальные люди не забывают проверять версию протокола при соединении.
    При обновлении кода клиента компилятор будет бить по рукам везде.

    На что я резонно заметил, что если эти два условия не выполняются, то протокол может быть четырежды статически типизированным, но его это не спасет.

    Два примера, что я приводил в развернутом виде выглядят так:

    Пример первый

    Наш код вызывает сторонний сервис через клиентскую библиотеку. Сторонний сервис написан на Java (!), клиентская библиотека — на Эрланге.

    Клиентская библиотека — это, по сути, один API вызов, который принимает на вход объект X, который проверяется на валидность, и потом отсылается в сторонний сервис.

    Пацаны из сервиса по какой-то причине подумали, что этим API-вызовом еще никто не пользуется и решили его улучшить (на самом деле) и заменить поле country_code с целого числа на ISO Alpha 2. И забыли обновить клиентскую библиотеку у нас.

    С нашей стороны ничего не изменилось: передаваемый в API объект с точки зрения библиотеки был абсолютно валидным. Она формировала с ее точки зрения абсолютно валидный объект для передачи в сервис. Сервис падал с HTTP 500 и стектрейсом, включающим в себя что-то типа IllegalArgumentException.

    Когда мы пришли к пацанам, реализующим сервис с вопросом «какого хрена», они слегка похватались за головы и быстренько выкатили для нас обновление своей библиотеки, которое добавляло конвертацию country_code:integer (который везде используется внутри нашей системы) в ISO Alpha 2 код (используемый сервисом). Код, вызывающий API этой библиотеки не надо было править нигде, от слова вообще. И наступило щастя.

    — Каким образом помогла бы стат. типизация, учитывая, что разработчики этого сервиса оказались «ненормальными», и внесли ломающие изменения в протокол без изменения версии и обновления клиентского кода? Да никак, от слова вообще.
    — Каким образом помогла бы стат. типизация нашему коду, если клиентская библиотека не обновлена? Да никак, от слова вообще. Да, она бы помогла при условии, если клиентская библиотека обновлена и ее интерфейс поменялся (и такие случаи бывают, и я про это говорил, что тогда стат. типизация весьма желанна).

    Пример второй

    На этот раз сервис предоставляем мы. На насквозь динамически типизированном эрланге. Но мы оказались, во-первых, «нормальными разработчиками»©™. Любые ломающие обратную совместимость изменения вводятся обязательно с изменением версии. Минимум две предыдущие версии продолжают поддерживаться.

    И IllegalArgumentException или что-либо подобное у нас невозможно вообще. Не из-за того, что язык динамически типизированный, а из-за того, что мы:
    — проверяем версии протокола
    — проверяем соотвествие присылаемых данных заявленной версии

    В случае несоответствия данные даже до собственно бизнес-кода не доходят, а возвращается предназначенная для этого ошибка HTTP 400 Bad Request с указанием, где именно проблемы. Еще раз. Это не ошибка из-за того, что в рантайме вместо типа X пришел тип Y, у нас вылетело исключение и мы трепыхаемся. Код, требующий тип X даже не увидит аргумент типа Y, потому что это дело отловит валидатор по схеме на самых ранних подступах.

    Так как у нас нет никакого контроля над клиентским кодом, то клиенты будут присылать все, что им в голову взбредет, потому что никто не защищен от «ненормальных разработчиков», кривых рук да и банальной реализации (абсолютно математически выверенной и статически типизированной, и скомпилированной) типа «отсылаем заголовок Content-Type одной версии, а тело запроса — другой».


    dmitriid.comGitHubLinkedIn
    Re[22]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 11.02.15 14:57
    Оценка:
    WH>Если код реализующий посылку сообщений генерируется из схемы, в которой прописаны все типы и номер версии, то такого быть не может.

    Если бы да кабы, да...

    В общем, ты сам рассказываешь о толпе предусловий, которые должны быть выполнены прежде, чем статическая типизация заработает, но почему-то сильно удивляешься, когда я указываю на эти условия и почему-то утверждаешь, что я в чем-то неправ


    dmitriid.comGitHubLinkedIn
    Re[23]: Про типы и логику
    От: WolfHound  
    Дата: 11.02.15 15:23
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>В общем, ты сам рассказываешь о толпе предусловий, которые должны быть выполнены прежде, чем статическая типизация заработает, но почему-то сильно удивляешься, когда я указываю на эти условия и почему-то утверждаешь, что я в чем-то неправ

    Я говорю всего про два:
    1)Программисты должны быть адекватны. Иначе в любом случае всё будет плохо.
    2)Статическая типизация должна быть.
    Жаловаться на то, что статическая типизация не работает, если её нет весьма странно.
    Твой второй пример именно про случай, когда её нет.
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[25]: Про типы и логику
    От: WolfHound  
    Дата: 11.02.15 16:36
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>«Адвекватность» программистов измеряется чем? Могу только повторить. Абсолютно адекватный, полностью статически проверенный код:

    В каком месте он адекватный?
    Где происходит статическая проверка схемы?

    А твоим методом можно легко обозвать любой динамически типизированный язык статически типизированным.

    M>В первом случае статическая типизация была, она сильно помогла?

    В первом случае был близкий аналог
    (B*)(void*)(new A())
    Те типы были выкинуты.
    Такое можно делать, только если есть железная гарантия что A == B.
    Разработчики её не обеспечили. Ессно код сломался.

    WH>> Твой второй пример именно про случай, когда её нет.

    M>Я не вижу, каким образом это «случай, когда ее нет». Ах да, мы упираемся в неизвестные критерии «адекватности программистов», ага
    Где происходит статическая проверка схемы?
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[14]: Про типы и логику
    От: genre Россия  
    Дата: 11.02.15 17:53
    Оценка:
    Здравствуйте, WolfHound, Вы писали:

    WH>JSON динамически типизированный.

    WH>Если бы протокол был статически типизирован

    А это как вообще?
    ... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
    Re[15]: Про типы и логику
    От: WolfHound  
    Дата: 11.02.15 18:03
    Оценка:
    Здравствуйте, genre, Вы писали:

    WH>>JSON динамически типизированный.

    WH>>Если бы протокол был статически типизирован
    G>А это как вообще?
    Примерно так: http://en.wikipedia.org/wiki/Interface_description_language
    ... << RSDN@Home 1.2.0 alpha 5 rev. 62>>
    Пусть это будет просто:
    просто, как только можно,
    но не проще.
    (C) А. Эйнштейн
    Re[26]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 12.02.15 21:21
    Оценка:
    M>>В первом случае статическая типизация была, она сильно помогла?
    WH>В первом случае был близкий аналог
    WH>(B*)(void*)(new A())
    WH>Те типы были выкинуты.

    С какого перепугу они были выкинуты? Ты придумываешь себе какие-то фантазии и упорно с ними борешься

    Как раз в первом случае стат. типизация помогла: не позволила проникнуть в код неправильному типу данных

    WH>>> Твой второй пример именно про случай, когда её нет.

    M>>Я не вижу, каким образом это «случай, когда ее нет». Ах да, мы упираемся в неизвестные критерии «адекватности программистов», ага
    WH>Где происходит статическая проверка схемы?

    Происходит проверка где?


    ЗЫ.

    Вообще, смешно наблюдать, что согласно тебе статическая типизация помогает строго в тепличных, приближенных к идеальным, лабораторных условиях:

    — программисты должны написать абсолютно корректный генератор кода по схеме
    — программисты должны привязать этот абсолютно корректный генератор кода по схеме к своей абсолютно корректной схеме данных
    — это должно произойти как на сервере, так и на клиенте
    — любые изменения, проводимые на сервере, должны моментально изменяться и обновляться на клиенте

    И только в этих тепличных условиях «компилятор бил бы по рукам разработчиков, которые пытаются сделать что-то не так, и данного класса проблем бы не было».

    Но в таких тепличных условиях не будет особых проблем с какой-либо типизацией


    dmitriid.comGitHubLinkedIn
    Re[2]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 04.03.15 04:33
    Оценка:
    Здравствуйте, alex_public, Вы писали:

    _>Здравствуйте, Mamut, Вы писали:


    _>Эх, что-то я со своим новым проектом так ушёл в дела, что совсем забыл про rsdn. А тут такие забавные вещи обсуждаются... Ну попробую влить новую кровь в затухающую дискуссию. )))


    _>Причём твой "Шаг1" отлично для этого подходит (на следующие шаги естественно это легко экстраполируется, но уже лень).



    Ну, начинается Вот не вижу я, чтобы он «естественно легко экстраполируется»


    Ну а по коду видно, что проверок стало в два раза больше, а простор для ошибок — точно такой же, как и без них

    _>P.S. В случае использования только известных на момент компиляции (т.е. не загружаемых из БД, а скажем создаваемых в коде) order'ов, все рантайм проверки можно полностью выкинуть из кода и тогда данный подход соответственно превращается из "необязательной дополнительной фичи" в наиболее оптимальное решение со всех точек зрения.


    За пределами теоретических изысканий таких Order'ов в природе не существует


    dmitriid.comGitHubLinkedIn
    Re[3]: Про типы и логику
    От: alex_public  
    Дата: 04.03.15 15:39
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Ну, начинается Вот не вижу я, чтобы он «естественно легко экстраполируется»


    Ну смотри, у тебя же классический конечный автомат из 3+1 состояний (3 реальных и 1 (Unknown) нужное для статической типизации), которые я все уже описал в коде. Ну точнее я не ввёл формально состояние Increase&Decrease, но только потому что там не было функции переводящей в него (мы же не можем сделать Unsend ордера). Соответственно какие бы сложные условия ты не добавлял на своих следующих шагах, это просто приведёт к усложнению кода перехода между состояними (грубо говоря твой "код в лоб" будет переноситься в некую сложную функцию типа CanDecrease, вызываемую в точке if(Type==OrderType::Unknown&&CanDecrease()) throw ... функции Decrease).

    Ты действительно видишь здесь что-то сложное? )

    M>Ну а по коду видно, что проверок стало в два раза больше, а простор для ошибок — точно такой же, как и без них


    Ну для начала статическая типизация не устраняет сами ошибки, а переводит их возникновение из времени исполнения во время компиляции. Что мы и видим в моём примере. Естественно переводятся во время компиляции только те проверки, для которых достаточно знаний на момент компиляции. Если в коде используется очень много рантайм данных, то никакая статическая типизация не позволит вынести много проверок во время компиляции. Но какие-то выносятся и в таком случае, что и демонстрирует мой пример. А вот если рантайм данных не много (ну в смысле не самих данных, а грубо говоря типов определяемых динамически), то подобный подход становится суперэффективным. С экстремум в виде 100% гарантии безошибочности кода при полном отсутствие динамически определяемых типов.

    Что касается количества проверок... Ты про что, про размер исходника или про нагрузку процессора в рантайме? ) Если про первое, то да, действительно размер исходника возрастает. Но это цена за перевод ошибок из времени исполнения во время компиляции. Если же говорить о втором, то там как раз количество рантайм проверок снижается (думаю же для тебе не откровения, что весь код после "if(X&&", где X — это false времени компиляции, компилятор полностью выкидывает? Кстати, в том же D это значительно нагляднее выглядит, благодаря наличию static if, но результат тот же самый), так что этот самый "разросшийся" код по быстродействию эффективнее твоего варианта "в лоб".

    _>>P.S. В случае использования только известных на момент компиляции (т.е. не загружаемых из БД, а скажем создаваемых в коде) order'ов, все рантайм проверки можно полностью выкинуть из кода и тогда данный подход соответственно превращается из "необязательной дополнительной фичи" в наиболее оптимальное решение со всех точек зрения.

    M>За пределами теоретических изысканий таких Order'ов в природе не существует

    Вообще то как раз существует и даже прямо в твоём случае. Например при создание нового ордера мы можем точно указать его тип и т.д. Проблема в том, что полностью уйти от рантайм данных в твоём случае нельзя и соответственно нельзя полностью убрать рантайм проверки. Но и частичный перевод ошибок во время компиляции тоже может быть полезен. )
    Отредактировано 04.03.2015 16:00 alex_public (нафиг оффтопик)) . Предыдущая версия .
    Re[5]: Про типы и логику
    От: alex_public  
    Дата: 04.03.15 16:51
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Так. Мой код будет перерастать во что-то сложное, а твой не будет? Можно это продемонстрировать? Да, я лично не вижу, как это экстраполируется


    Ты не понял мою мысль. Вот смотри, у меня сейчас есть пример для простейшей бизнес-логики. Дальше, берём относительно сложный случай (твой шаг3 скажем) и берём твой сложный код "в лоб" для этого случая. Так вот нам понадобится просто вставить этот твой сложный код прямо в определённую точку моего простого примера. Понятная идея? ) Т.е. грубо говоря при усложнение задачи объём дополнительного кода (возникающего ради статического отлова ошибок) не будет возрастать (относительного моего примера).

    M>Ну, я имею в виду, что в твоем примере все равно все упирается в то, расставил ли кто-нибудь static_assert'ы по коду. Если по коду есть хотя бы минимальное тестирование (а логику проверять надо), то их полезность по сравнению с динамической типизацией падает экспоненциально. И как показывает твой пример, нам все равно надо отлавливать рантайм-ошибки в зависимости от того, как эти ассерты расставлены. В итоге ответсвенность за логику размыта и стало сложнее проследить, а не забыли ли мы что-либо и правильно ли мы реализовали логику.


    Ты похоже тут уже пытаешься решить совсем другую задачу. Не перенос проверок ошибок из времени исполнения во время компиляции, а некую попытку статической проверки полноты проверок времени исполнения. О таком в принципе тоже можно подумать... Но я не уверен, что даже теоретически возможно какое-то полноценное решение, т.к. при любой типизации и вообще архитектуре всё равно будет некая точка для задания набора "правил" нашей логики. И если забыть задать их там, то по идее никто не способен отловить этот факт. Максимум, что могут наши современные средства, это свести введение правил до действительно одной точки, с автоматическим расползанием их по всему коду. И как раз в таком статическая типизация очень помогает.

    _>>Что касается количества проверок... Ты про что, про размер исходника или про нагрузку процессора в рантайме? )

    M>Нет. Я имел в виду, что вижу по два if'а (грубо говоря) на каждую функцию

    Ну в исполняемый файл в итоге попадает или один или ноль if'ов. А в исходнике да, разрастаемся... )))

    _>>Вообще то как раз существует и даже прямо в твоём случае. Например при создание нового ордера мы можем точно указать его тип и т.д.

    M>Теоретики такие теоретики. Новый заказ создается из 100% рантайм-данных. И, соотвественно, наделяется всеми свойствами исключительно в рантайме.

    Ничего подобного. В коде ты легко можешь создать пустой экземпляр ордера (и у него уже не будет тип Unknown, а будет скажем IncreaseDecrease), а потом заполнить его своими рантайм данными с помощью тех же самых функций перевода состояния. И при этом будут автоматически производиться все проверки.
    Re[6]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 04.03.15 18:21
    Оценка:
    M>>Так. Мой код будет перерастать во что-то сложное, а твой не будет? Можно это продемонстрировать? Да, я лично не вижу, как это экстраполируется

    _>Ты не понял мою мысль.


    Я ее понял

    _>Вот смотри, у меня сейчас есть пример для простейшей бизнес-логики. Дальше, берём относительно сложный случай (твой шаг3 скажем) и берём твой сложный код "в лоб" для этого случая. Так вот нам понадобится просто вставить этот твой сложный код прямо в определённую точку моего простого примера. Понятная идея? ) Т.е. грубо говоря при усложнение задачи объём дополнительного кода (возникающего ради статического отлова ошибок) не будет возрастать (относительного моего примера).


    Можно это увидеть на полноценном примере? Там всего-то несколько усложнений по сравнению с реальностью

    M>>И как показывает твой пример, нам все равно надо отлавливать рантайм-ошибки в зависимости от того, как эти ассерты расставлены. В итоге ответсвенность за логику размыта и стало сложнее проследить, а не забыли ли мы что-либо и правильно ли мы реализовали логику.


    _>Ты похоже тут уже пытаешься решить совсем другую задачу.


    Да нет. Все ту же Я просто говорю, что твой пример показывает, что с точки зрения программиста все стало сложнее. Где мы проверяем условия статически? А где — в рантайме? Не маскирует ли стат. типизация необходимую проверку в рантайме? В нужном ли месте я поставил стат. типизацию, и правильно ли, что во втором твоем примере происходит рантайм проверка? С ростом количества условий это превратится в непонятный никому звиздец, имхо.

    А как только для разруливания и проверки этого звиздеца мы вставляем тесты, как ценность стат. проверок начинает падать экспоненциально.

    _>Максимум, что могут наши современные средства, это свести введение правил до действительно одной точки, с автоматическим расползанием их по всему коду. И как раз в таком статическая типизация очень помогает.


    Не понял этой фразы и утверждения

    _>>>Что касается количества проверок... Ты про что, про размер исходника или про нагрузку процессора в рантайме? )

    M>>Нет. Я имел в виду, что вижу по два if'а (грубо говоря) на каждую функцию

    _>Ну в исполняемый файл в итоге попадает или один или ноль if'ов. А в исходнике да, разрастаемся... )))


    Ну, вообще-то по большому счету глубоко наплевать на то, что попадает в исполняемый файл. Время программиста, который будет все это писать и разбирать потом, важнее намного.

    _>>>Вообще то как раз существует и даже прямо в твоём случае. Например при создание нового ордера мы можем точно указать его тип и т.д.

    M>>Теоретики такие теоретики. Новый заказ создается из 100% рантайм-данных. И, соотвественно, наделяется всеми свойствами исключительно в рантайме.

    _>Ничего подобного. В коде ты легко можешь создать пустой экземпляр ордера (и у него уже не будет тип Unknown, а будет скажем IncreaseDecrease), а потом заполнить его своими рантайм данными с помощью тех же самых функций перевода состояния. И при этом будут автоматически производиться все проверки.


    Так. Я про это и говорю: данные приходят строго из рантайма. Про «функции перевода состояния» я слышу уже скоро месяц, как, но никто так и не осилил описать эти «функции состояния» до уровня полноценного примера

    И вообще. Что значит «функции состояния»? У нас нет никаких «функций перехода состояния». Изменение суммы заказа может происходить через неделю после того, как заказ создан. При чем тут «функции состояния»? Перед тем, как изменить сумму заказа, заказ будет загружен из базы данных в любом из четырех (из примера) или полутора десятков (в реальности) состояний.

    Тут рядом Sinclair недаром просил показать функцию load_order для примера jazzer'а


    dmitriid.comGitHubLinkedIn
    Re[7]: Про типы и логику
    От: alex_public  
    Дата: 04.03.15 19:22
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Можно это увидеть на полноценном примере? Там всего-то несколько усложнений по сравнению с реальностью


    Да просто добавляешь свои обычные рантайм проверки в функции Decrease и Increase. Ничего касающегося статической типизации там больше не видно. К сожалению. ))) Потому как чем больше можно перевести в статику, тем лучше.

    M>Да нет. Все ту же Я просто говорю, что твой пример показывает, что с точки зрения программиста все стало сложнее. Где мы проверяем условия статически? А где — в рантайме? Не маскирует ли стат. типизация необходимую проверку в рантайме? В нужном ли месте я поставил стат. типизацию, и правильно ли, что во втором твоем примере происходит рантайм проверка? С ростом количества условий это превратится в непонятный никому звиздец, имхо.


    Я тебе уже в который раз говорю, что сложность не увеличится (более моего первого примера). Другое дело, что для твоей задачки польза от всего этого не особо есть и смысл играться с таким есть только ради демонстрации принципа на форуме. Но это в твоей задачке, а есть же много других. )))

    M>А как только для разруливания и проверки этого звиздеца мы вставляем тесты, как ценность стат. проверок начинает падать экспоненциально.


    Ну у тестов имеются горы своих специфических проблем... )

    _>>Максимум, что могут наши современные средства, это свести введение правил до действительно одной точки, с автоматическим расползанием их по всему коду. И как раз в таком статическая типизация очень помогает.

    M>Не понял этой фразы и утверждения

    Если у нас есть какие-то ограничения на бизнес-логику (например как в твоей задачке — "отправленное нельзя увеличивать"), то очевидно лучше чтобы сам код проверки был написан ровно в одной точке программы, вызываясь из всех нужных мест. Статическая типизация отлично подходит для таких стратегий. Более того, она может ещё проконтролировать, чтобы не было мест без вызова проверки. Хотя это естественно не единственный способ реализации.

    _>>Ну в исполняемый файл в итоге попадает или один или ноль if'ов. А в исходнике да, разрастаемся... )))

    M>Ну, вообще-то по большому счету глубоко наплевать на то, что попадает в исполняемый файл. Время программиста, который будет все это писать и разбирать потом, важнее намного.

    В твоей задаче — конечно. А в других вполне бывает что всё наоборот.

    M>Так. Я про это и говорю: данные приходят строго из рантайма. Про «функции перевода состояния» я слышу уже скоро месяц, как, но никто так и не осилил описать эти «функции состояния» до уровня полноценного примера


    Ну вот прямо в моём примере видны эти функции. Например функция SendOrder переводит из состояния Unknown (ну и не заданного мною Increase&Decrease) в состояние OnlyDecrease.

    M>И вообще. Что значит «функции состояния»? У нас нет никаких «функций перехода состояния». Изменение суммы заказа может происходить через неделю после того, как заказ создан. При чем тут «функции состояния»? Перед тем, как изменить сумму заказа, заказ будет загружен из базы данных в любом из четырех (из примера) или полутора десятков (в реальности) состояний.


    И? ) Не пойму с чем ты споришь то? ) Я разве утверждал, что весь твой пример можно покрыть статикой? ) Естественно там останется куча рантайм проверок. Я просто поясняю, что статические тоже будут встречаться и не так редко, как ты думаешь. Но всё же наверное недостаточно часто, чтобы делать подобное в твоём случая. А вот в других задачах, где процент повыше, это уже явно имеет смысл.

    Однако тут то у нас форум и вопрос стоял (как я понял) не в несообразности применения данной технологии к конкретной задаче, а в демонстрации самой возможности подобного и механизма действия. С этим вроде как мой пример полностью справляется.
    Re[8]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 04.03.15 21:46
    Оценка:
    M>>Можно это увидеть на полноценном примере? Там всего-то несколько усложнений по сравнению с реальностью

    _>Да просто добавляешь свои обычные рантайм проверки в функции Decrease и Increase.



    Если это так просто, можно наконец увидеть законченный пример?

    _>Ничего касающегося статической типизации там больше не видно. К сожалению. ))) Потому как чем больше можно перевести в статику, тем лучше.


    Ну так переводи

    _>Я тебе уже в который раз говорю, что сложность не увеличится (более моего первого примера). Другое дело, что для твоей задачки польза от всего этого не особо есть и смысл играться с таким есть только ради демонстрации принципа на форуме. Но это в твоей задачке, а есть же много других. )))


    Приводи другие задачи

    _>>>Максимум, что могут наши современные средства, это свести введение правил до действительно одной точки, с автоматическим расползанием их по всему коду. И как раз в таком статическая типизация очень помогает.

    M>>Не понял этой фразы и утверждения

    _>Если у нас есть какие-то ограничения на бизнес-логику (например как в твоей задачке — "отправленное нельзя увеличивать"), то очевидно лучше чтобы сам код проверки был написан ровно в одной точке программы, вызываясь из всех нужных мест. Статическая типизация отлично подходит для таких стратегий. Более того, она может ещё проконтролировать, чтобы не было мест без вызова проверки. Хотя это естественно не единственный способ реализации.



    Ахахахахахахахахаха Вы уже договоритесь между собой, подходит или не подходит. Тут рядом Evgeny.Panasyuk утверждал, что в моем случае стат. типизация бессмысленна именно потому что все проверки были перенесены в одну функцию

    _>>>Ну в исполняемый файл в итоге попадает или один или ноль if'ов. А в исходнике да, разрастаемся... )))

    M>>Ну, вообще-то по большому счету глубоко наплевать на то, что попадает в исполняемый файл. Время программиста, который будет все это писать и разбирать потом, важнее намного.

    _>В твоей задаче — конечно. А в других вполне бывает что всё наоборот.


    В подавляющем большинстве задач именно так.


    M>>Так. Я про это и говорю: данные приходят строго из рантайма. Про «функции перевода состояния» я слышу уже скоро месяц, как, но никто так и не осилил описать эти «функции состояния» до уровня полноценного примера


    _>Ну вот прямо в моём примере видны эти функции. Например функция SendOrder переводит из состояния Unknown (ну и не заданного мною Increase&Decrease) в состояние OnlyDecrease.


    Это они видны в твоем примере, потому что тебе так удобно. На практике SendOrder запишет в заказе поле is_sent=true и запишет в базу. Изменение суммы заказа, повторю, может произойти через неделю после того, как заказ отправился. И никаким переведением в «OnlyDecrease» SendOrder не будет заниматься, потому что это не ее область ответственности.

    M>>И вообще. Что значит «функции состояния»? У нас нет никаких «функций перехода состояния». Изменение суммы заказа может происходить через неделю после того, как заказ создан. При чем тут «функции состояния»? Перед тем, как изменить сумму заказа, заказ будет загружен из базы данных в любом из четырех (из примера) или полутора десятков (в реальности) состояний.


    _>И? ) Не пойму с чем ты споришь то? ) Я разве утверждал, что весь твой пример можно покрыть статикой? )


    На данный момент я спорю с твоим странным утверждением о «функциях состяний» и прочем, извини, бреде, который при малейшем толчке рассыпается в прах.

    Ты взял удобный тебе пример, когда все подряд идет подряд и показываешь, как это мегакруто. Извини. На практике ничего подобного не бывает.

    Данные получаются откуда угодно, но только не из этапа компиляции, объекты находятся в сотне изменяемых и неизменяемых состяний, часто противоречащих друг другу, и эти состояния зависят от нескольких десятков разнообразных параметров, половина которых — из базы данных, вторая — из-за конфигурации, а третья — из выставленных где-нибудь в GUI оверрайдов.

    В итоге и получается: как только удобные вам примеры уровня hello world'а, то — ура, ура, посмотри какая статика крутая. Как только пытаешься выйти за пределы уютного мирка, где все известно заранее, на этапе компиляции, как все: «не, ну мы тебе ничего не обещали, тут дальше очевидно, достаточно сделать метасвойство» и прочая и прочая

    _>Естественно там останется куча рантайм проверок. Я просто поясняю, что статические тоже будут встречаться и не так редко, как ты думаешь. Но всё же наверное недостаточно часто, чтобы делать подобное в твоём случая. А вот в других задачах, где процент повыше, это уже явно имеет смысл.


    Так приведи эти задачи. Где они? Ну, такие, не сугубо теоретические, а что-то связанное с тем, чем тут большинство занимается: перекладыванием одних данных в другие. Опять же, рядом где-то на сотой странице обсуждений смогли осилить только boost timer, где афинные преобразования применяются (я, правда, не понял, в чем именно там проявляется мощь стат. типизации, ну да ладно)

    _>Однако тут то у нас форум и вопрос стоял (как я понял) не в несообразности применения данной технологии к конкретной задаче, а в демонстрации самой возможности подобного и механизма действия. С этим вроде как мой пример полностью справляется.


    Нет, не справляется. Потому что моментально рассыпается от малейших прикосновений:
    — у нас нет прямого перехода от sendorder в decrease и т.п.
    — у нас order не создается на этапе компиляции, а из 100% рантайм-данных, после чего кладется в базу
    и т.п.



    Пока что «примеры, прекрасно показывающие», имеют какие-то сугубо теоретические основы или странные требования.


    dmitriid.comGitHubLinkedIn
    Re[9]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 04.03.15 22:27
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Тут рядом Evgeny.Panasyuk утверждал, что в моем случае стат. типизация бессмысленна именно потому что все проверки были перенесены в одну функцию


    Перенесены в функцию у которой нет соответствующих предусловий.
    Если предусловия всё-таки есть, а внутренние проверки это всего лишь defensive programming, а отнюдь не разветвление в соответствии с контрактом функции — то смысл есть.

    M>Опять же, рядом где-то на сотой странице обсуждений смогли осилить только boost timer,


    std::chrono

    M>где афинные преобразования применяются (я, правда, не понял, в чем именно там проявляется мощь стат. типизации, ну да ладно)


    В аффинном пространстве есть точки и векторы. Складывать две точки нельзя, разница двух точек это вектор, сумма точки и вектора — точка, линейная комбинация векторов — вектор. Статическая типизация, помимо всего прочего, позволяет закодировать эту логику и проверять её во время компиляции.
    Re[10]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.03.15 09:19
    Оценка:
    M>>Тут рядом Evgeny.Panasyuk утверждал, что в моем случае стат. типизация бессмысленна именно потому что все проверки были перенесены в одну функцию

    EP>Перенесены в функцию у которой нет соответствующих предусловий.




    EP>Если предусловия всё-таки есть, а внутренние проверки это всего лишь defensive programming, а отнюдь не разветвление в соответствии с контрактом функции — то смысл есть.


    Специально для тебя терпеливо, как ребенку объясняю:

    У тебя было:

    
    function a(){    | function b(){    | 
                     |                  |
       if            |    if            |  
       if            |    if            | 
       if            |    if            | 
       if            |    if            | 
                     |                  |
                     |                  |
       x()           |    x()           |
                     |                  |
    }                | }                |



    Тут ты говоришь: «ах-ах-ах, предусловия, как стат. типизация помогает-то!»

    Делаем простой фокус, следи за руками:

    
    function a(){    | function b(){    |  function z(){    | 
                     |                  |                   |
       z()           |   z()            |     if            |  
                     |                  |     if            | 
                     |                  |     if            | 
                     |                  |     if            | 
                     |                  |                   |
                     |                  |                   |
                     |                  |     x()           | 
                     |                  |                   |
    }                | }                | }                 |



    Ой. Ничего не изменилось. Все условия на месте. Но только ВНЕЗАПНО «не, не имеет смысла».

    При том, что jazzer и alex_public и AlexRK наперебой утверждают, что нет, имеет смыл


    M>>Опять же, рядом где-то на сотой странице обсуждений смогли осилить только boost timer,

    EP>std::chrono

    Не суть важно.

    M>>где афинные преобразования применяются (я, правда, не понял, в чем именно там проявляется мощь стат. типизации, ну да ладно)


    EP>В аффинном пространстве есть точки и векторы. Складывать две точки нельзя, разница двух точек это вектор, сумма точки и вектора — точка, линейная комбинация векторов — вектор. Статическая типизация, помимо всего прочего, позволяет закодировать эту логику и проверять её во время компиляции.


    Ну в общем это все упирается только в «если у нас все абсолютно доступно во время компиляции». Да, это приятно, не скрою. Но нам, например, от этого ни холодно ни жарко


    dmitriid.comGitHubLinkedIn
    Отредактировано 10.03.2015 13:54 Mamut [ищите в других сетях] . Предыдущая версия . Еще …
    Отредактировано 05.03.2015 20:42 Mamut [ищите в других сетях] . Предыдущая версия .
    Re[11]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 05.03.15 10:30
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Ой. Ничего не изменилось. Все условия на месте. Но только ВНЕЗАПНО «не, не имеет смысла».


    Бывают предусловия, бывает необязательный defensive programming для проверки некоторых из предусловий (при этом не являющийся частью контракта), бывают обычные внутренние условия/разветвления соответствующие контракту функции.
    Ты понимаешь разницу между предусловием и простым if'ом внутри или снаружи функции? Без согласия в терминологии не вижу смысла продолжать ходить по кругу.

    M>>>где афинные преобразования применяются (я, правда, не понял, в чем именно там проявляется мощь стат. типизации, ну да ладно)

    EP>>В аффинном пространстве есть точки и векторы. Складывать две точки нельзя, разница двух точек это вектор, сумма точки и вектора — точка, линейная комбинация векторов — вектор. Статическая типизация, помимо всего прочего, позволяет закодировать эту логику и проверять её во время компиляции.
    M>Ну в общем это все упирается только в «если у нас все абсолютно доступно во время компиляции». Да, это приятно, не скрою. Но нам, например, от этого ни холодно ни жарко

    А я уже показывал
    Автор: Evgeny.Panasyuk
    Дата: 10.02.15
    полный рабочий пример в котором N псевдослучайных runtime флагов переводятся в compile-time значения, то есть в значения доступные во время компиляции
    Re[12]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.03.15 11:58
    Оценка:
    EP>Ты понимаешь разницу между предусловием и простым if'ом внутри или снаружи функции? Без согласия в терминологии не вижу смысла продолжать ходить по кругу.

    Я вижу, что ничего не изменилось. И все те же «предусловия» для функции x() никуда не делись. Они становятся «бессмысленными» только у тебя

    M>>Ну в общем это все упирается только в «если у нас все абсолютно доступно во время компиляции». Да, это приятно, не скрою. Но нам, например, от этого ни холодно ни жарко


    EP>А я уже показывал
    Автор: Evgeny.Panasyuk
    Дата: 10.02.15
    полный рабочий пример в котором N псевдослучайных runtime флагов переводятся в compile-time значения, то есть в значения доступные во время компиляции


    Что именно в этом примере нам дает стат. типизация? Да, я тупой. Я не понимаю, зачем это нужно.


    dmitriid.comGitHubLinkedIn
    Re[13]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 05.03.15 12:12
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>>>Ну в общем это все упирается только в «если у нас все абсолютно доступно во время компиляции». Да, это приятно, не скрою. Но нам, например, от этого ни холодно ни жарко

    EP>>А я уже показывал
    Автор: Evgeny.Panasyuk
    Дата: 10.02.15
    полный рабочий пример в котором N псевдослучайных runtime флагов переводятся в compile-time значения, то есть в значения доступные во время компиляции

    M>Что именно в этом примере нам дает стат. типизация? Да, я тупой. Я не понимаю, зачем это нужно.

    Контекст достаточно прямолинеен:

    1. Я показал пример с аффинным пространством.
    2. Ты согласился с тем что в этом примере часть логики легко закодировать в типах, так? Но говоришь что это нещитово, так как в этом примере всё доступно во времени компиляции, а тебя интересуют runtime данные.
    3. Я привожу пример перевода совершенно случайных runtime значений в значения доступные во время компиляции. Это всего лишь техника.
    Re[9]: Про типы и логику
    От: alex_public  
    Дата: 05.03.15 12:30
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    M>Если это так просто, можно наконец увидеть законченный пример?


    Подметать двор тоже просто, но мало кто стремиться позаниматься этим. )

    _>>Ничего касающегося статической типизации там больше не видно. К сожалению. ))) Потому как чем больше можно перевести в статику, тем лучше.

    M>Ну так переводи

    В смысле? ) Я же говорю, в твоём примере в статику переводится только небольшая часть (и это уже продемонстрировано). Т.е. хотелось бы больше, но не выйдет.

    M>Приводи другие задачи


    Другие задачи для чего? ) Для демонстрации эффективности статической типизации вообще (тут я прямо даже не знаю за что сразу хвататься, столько вариантов)? Или же ты про что-то конкретное?

    M>Ахахахахахахахахаха Вы уже договоритесь между собой, подходит или не подходит. Тут рядом Evgeny.Panasyuk утверждал, что в моем случае стат. типизация бессмысленна именно потому что все проверки были перенесены в одну функцию


    Объявляться правила должны в одном месте, а использоваться во многих. Именно в такой ситуации задание правил с помощью типов максимально эффективно.

    M>В подавляющем большинстве задач именно так.


    Ага, ага))) Ну только если не считать задачи типа как у Гугла/Яндекса (т.к. там 1% производительности означает сотни дополнительных серверов), научные числодробилки (кого-то волнуют дополнительные несколько недель вычислений?), задачи для мобильных устройств (т.к. там неэффективный код сжирает аккумулятор), задачи для встроенных устройств (т.к. там может банально не хватить ресурсов на исполнение) и т.п... А так да конечно, время программиста "почти всегда" важнее эффективности кода.

    M>Это они видны в твоем примере, потому что тебе так удобно. На практике SendOrder запишет в заказе поле is_sent=true и запишет в базу. Изменение суммы заказа, повторю, может произойти через неделю после того, как заказ отправился. И никаким переведением в «OnlyDecrease» SendOrder не будет заниматься, потому что это не ее область ответственности.


    Вообще то все эти состояния существуют только на момент компиляции. ))) Однако в твоём случае это действительно всё не в тему (см. ниже).

    M>Так приведи эти задачи. Где они? Ну, такие, не сугубо теоретические, а что-то связанное с тем, чем тут большинство занимается: перекладыванием одних данных в другие. Опять же, рядом где-то на сотой странице обсуждений смогли осилить только boost timer, где афинные преобразования применяются (я, правда, не понял, в чем именно там проявляется мощь стат. типизации, ну да ладно)


    С чего ты взял, что тут большинство занимается перекладыванием одних данных в другие? ) К примеру у меня подобной фигни нигде не наблюдается. Ну разве что в паре мелких серверных скриптов на наших сайтах помню подобный код. )))

    Да, и я так и не понял, ты хочешь поговорить о преимуществах статической типизации вообще (странно что у кого-то вообще могут быть сомнения по такому вопросу)??? Или же всё же о каких-то конкретных специфических применения?

    _>>Однако тут то у нас форум и вопрос стоял (как я понял) не в несообразности применения данной технологии к конкретной задаче, а в демонстрации самой возможности подобного и механизма действия. С этим вроде как мой пример полностью справляется.

    M>Нет, не справляется. Потому что моментально рассыпается от малейших прикосновений:
    M>- у нас нет прямого перехода от sendorder в decrease и т.п.
    Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?
    M>- у нас order не создается на этапе компиляции, а из 100% рантайм-данных, после чего кладется в базу
    А это и не требуется для работы.

    M>Пока что «примеры, прекрасно показывающие», имеют какие-то сугубо теоретические основы или странные требования.


    Да на самом деле проблема в другом. Я тут перечитал твои сообщения и понял, что ты хочешь получить от людей совсем другое. Можно сказать даже более тривиальное. А тебе показывают сложное и из другой области. Тебе продемонстрировали возможности перевода части проверок в статику (а это очень круто по целому ряду причин), причём для сложных алгоритмов. А тебе то хочется совсем другого, более простого — некой помощи в организации сложных рантайм проверок (а не переноса их в статику), причём для тривиальной задачи вида "загрузка из БД, элементарная операция (с проверкой возможности), сохранение в БД". Естественно, что тебя не впечатляют показанные примеры. Надо будет подумать, что может предложить статическая типизация для твоей простенькой проблемы... Возможно есть какие-то варианты со статическом анализом операций (тогда типами будут уже не ордера, а операции), но так с ходу не придумывается. )))
    Re[10]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.03.15 13:41
    Оценка:
    _>Да, и я так и не понял, ты хочешь поговорить о преимуществах статической типизации вообще (странно что у кого-то вообще могут быть сомнения по такому вопросу)??? Или же всё же о каких-то конкретных специфических применения?

    Выделенное — это сфероконь. Иначе известный, как теория. Теория без практики мертва.

    Мне тут на протяжение двух сотен сообщений заливают баки про это самое «вообще». Можно меньше слов и больше дела?

    M>>- у нас нет прямого перехода от sendorder в decrease и т.п.

    _>Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?

    Достаточно ограничить твои рассуждения про состояния этой саомй элементарной операцией, и все твои построения рушатся, как карточный домик

    Я умолчу, что краткое описание «всего лишь» SendOrder — это почти 100 пунктов, многие из которых не элементарны.

    M>>- у нас order не создается на этапе компиляции, а из 100% рантайм-данных, после чего кладется в базу

    _>А это и не требуется для работы.

    M>>Пока что «примеры, прекрасно показывающие», имеют какие-то сугубо теоретические основы или странные требования.


    _>Да на самом деле проблема в другом. Я тут перечитал твои сообщения и понял, что ты хочешь получить от людей совсем другое. Можно сказать даже более тривиальное. А тебе показывают сложное и из другой области.


    Мне ничего не показывают Кроме Евгения.

    _>Тебе продемонстрировали возможности перевода части проверок в статику (а это очень круто по целому ряду причин), причём для сложных алгоритмов. А тебе то хочется совсем другого, более простого — некой помощи в организации сложных рантайм проверок


    Стоп. Вот у меня есть «сложная рантайм проверка». Ее никто не осилил. Но я должен поверить, ага-ага, что будет «некая помощь» в «сложных рантайм проверках» в «нетривиальных примерах».



    Пожалуйста. Вот тебе «менее тривиальный» пример
    Автор: Mamut
    Дата: 06.02.15
    . Я могу специально для тебя выложить flow нашей функции SendOrder. Да ты и другие пропоненты стат. типизации же просто загнутся решать «организацию сложных рантайм проверок».


    _>Естественно, что тебя не впечатляют показанные примеры. Надо будет подумать, что может предложить статическая типизация для твоей простенькой проблемы...


    Для начала можно подумать над тем, почему постоянно выдвигаются взимноисключающие параграфы.
    И да. Ты и другие не осилили «простенькую проблему», но да, но да. «помогает в организации сложных рантайм проверок». Сказки этажом выше.

    _>Возможно есть какие-то варианты со статическом анализом операций (тогда типами будут уже не ордера, а операции), но так с ходу не придумывается. )))


    Я и заметил, что «с ходу не придумывается». Причем ни у кого. А пафоса-то! А громких заявлений!


    dmitriid.comGitHubLinkedIn
    Re[14]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 05.03.15 13:42
    Оценка:
    EP>3. Я привожу пример перевода совершенно случайных runtime значений в значения доступные во время компиляции. Это всего лишь техника.

    Объясни мне, что тут происходит, и как это может применяться. Можно на моем примере, можно не на моем.


    dmitriid.comGitHubLinkedIn
    Re[11]: Про типы и логику
    От: alex_public  
    Дата: 06.03.15 00:25
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    _>>Да, и я так и не понял, ты хочешь поговорить о преимуществах статической типизации вообще (странно что у кого-то вообще могут быть сомнения по такому вопросу)??? Или же всё же о каких-то конкретных специфических применения?

    M>Выделенное — это сфероконь. Иначе известный, как теория. Теория без практики мертва.

    Не совсем. Статическая типизация — это настолько глобальная вещь, что у неё есть и соответственно глобальные преимущества (а не только появляющиеся при рассмотрение конкретных случаев). Например, она на корню устраняет целый класс ошибок программиста. Всегда и везде. Конечно ты можешь вспомнить про тесты, как про сомнительную альтернативу... Но во-первых их надо писать (т.е. тратить время на дополнительные ненужные тесты, не относящиеся к функциональности), а во-вторых нет никаких гарантий их полноты. Это так сказать базовое преимущество, даваемое автоматически даже самому новичку в программирование, а не всяческие хитрые извращения (когда мы пытаемся накрутить проверку ещё и своих хитрых правил, а не только вложенных в систему обычных типов), обсуждаемые в данной темке.

    M>Мне тут на протяжение двух сотен сообщений заливают баки про это самое «вообще». Можно меньше слов и больше дела?


    Я в связи с занятостью по организации нового проекта так и не прочитал соседнюю темку ещё. ) А с чего собственно начался спор? )

    _>>Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?

    M>Достаточно ограничить твои рассуждения про состояния этой саомй элементарной операцией, и все твои построения рушатся, как карточный домик

    Ну так достаточно наличия хотя бы двух элементарных операций на одном шаге, чтобы продемонстрированная мною технология заработала.

    M>Я умолчу, что краткое описание «всего лишь» SendOrder — это почти 100 пунктов, многие из которых не элементарны.


    Ты же вроде сам писал, что SendOrder — это всего лишь sent=true и потом сохранения ордера в базу. Так где истина то у тебя? )

    _>>Тебе продемонстрировали возможности перевода части проверок в статику (а это очень круто по целому ряду причин), причём для сложных алгоритмов. А тебе то хочется совсем другого, более простого — некой помощи в организации сложных рантайм проверок

    M>Стоп. Вот у меня есть «сложная рантайм проверка». Ее никто не осилил. Но я должен поверить, ага-ага, что будет «некая помощь» в «сложных рантайм проверках» в «нетривиальных примерах».
    M>

    Ты как-то криво читаешь мой текст. Здесь под сложностью/простотой задачи подразумевается не размер твоего алгоритма, а то, что мы хотим с ним сделать. Перевести часть его во время компиляции — это сложная задача (вне зависимости от количества проверок). Которая не всегда реализуема (во всяком случае целиком), но приносящая много бонусов в случае успеха. Однако демонстрация этого тебя абсолютно не впечатляет, просто потому, что тебе хочется видоизменить свой алгоритм в совсем другом направление — просто несколько упорядочить его (чтобы не было пропущенных рантайм проверок например), а количество рантайм проверок не важно. Это очевидно задача другого класса, гораздо более простая, выполнимая и скорее относящаяся к культуре проектирования. Другое дело, что не факт что статическая типизация будет иметь какое-то отношения к этому. Хотя не знаю, может и с помощью неё есть какие-то решения. Я не готов с ходу ответить, т.к. не обдумывал ещё данное направление.

    M>Пожалуйста. Вот тебе «менее тривиальный» пример
    Автор: Mamut
    Дата: 06.02.15
    . Я могу специально для тебя выложить flow нашей функции SendOrder. Да ты и другие пропоненты стат. типизации же просто загнутся решать «организацию сложных рантайм проверок».


    Вообще то это тривиально реализуется даже прямо на том моём простейшем примере. Потому как у тебя тут не появляется никаких новых состояний (всё тоже самое — можно менять сумму или нельзя). А количество условий для перехода между состояниями вообще не принципиально. Оно же всё равно записывается тем же самым тупым кодом в лоб (без всяких игр с типами), прямо как и у тебя. Просто там в итоге будет не true/false, а тип такой или тип другой.

    Однако это я опять же о своём, об интересной задачке переноса вычислений в статику. А тебе то это не интересно, тебе то хочется как-то уменьшить число ошибок в том самом тупом коде рантайм проверки этого множества условий...

    M>Для начала можно подумать над тем, почему постоянно выдвигаются взимноисключающие параграфы.

    M>И да. Ты и другие не осилили «простенькую проблему», но да, но да. «помогает в организации сложных рантайм проверок». Сказки этажом выше.

    Надо просто внимательнее читать текст оппонентов (см. выше), тогда не будет недопонимания. )

    _>>Возможно есть какие-то варианты со статическом анализом операций (тогда типами будут уже не ордера, а операции), но так с ходу не придумывается. )))

    M>Я и заметил, что «с ходу не придумывается». Причем ни у кого. А пафоса-то! А громких заявлений!

    Ну я вроде как ничего не заявлял))) Я только показал пример, демонстрирующий перевод части рантайм проверок во время компиляции. Причём не на каком-то своём удобном примере, а на совсем неудобном твоём, показав что и там такое возможно. В начале мне показалась что цель именно в этом (т.к. она более нетривиальная и интересная). Теперь я вижу, что тебя интересовало другое и для твое проблемы (не задачки, а того, что надо с ней сделать!) у меня рецептов завязанных на статическую типизацию (а не на организационно-архитектурные улучшения, например типа перехода на использование некого встроенного DSL) с ходу нет. Но это не значит что их не существует. ))) И возможно даже я сам ещё что-то предложу, если найду время на обдумывание этой проблемы.
    Re[12]: Про типы и логику
    От: Mamut Швеция http://dmitriid.com
    Дата: 06.03.15 12:56
    Оценка:
    _>>>Да, и я так и не понял, ты хочешь поговорить о преимуществах статической типизации вообще (странно что у кого-то вообще могут быть сомнения по такому вопросу)??? Или же всё же о каких-то конкретных специфических применения?
    M>>Выделенное — это сфероконь. Иначе известный, как теория. Теория без практики мертва.

    _>Не совсем. Статическая типизация — это настолько глобальная вещь, что у неё есть и соответственно глобальные преимущества (а не только появляющиеся при рассмотрение конкретных случаев). Например, она на корню устраняет целый класс ошибок программиста. Всегда и везде.


    Громогласные заявления и пафос. Да, устраняют. Нет, этот класс ошибок не является самым большим.

    _>Конечно ты можешь вспомнить про тесты, как про сомнительную альтернативу... Но во-первых их надо писать


    Их все равно надо писать. Реализованная на типах логика автоматически правильной не становится.

    M>>Мне тут на протяжение двух сотен сообщений заливают баки про это самое «вообще». Можно меньше слов и больше дела?

    _>Я в связи с занятостью по организации нового проекта так и не прочитал соседнюю темку ещё. ) А с чего собственно начался спор? )

    Самое-самое начало тут: http://rsdn.ru/forum/philosophy/5941462
    Автор: Mamut
    Дата: 02.02.15

    Сведенные воедино самые пафосные заявления тут: http://rsdn.ru/forum/philosophy/5946930.1
    Автор: Mamut
    Дата: 07.02.15



    _>>>Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?

    M>>Достаточно ограничить твои рассуждения про состояния этой саомй элементарной операцией, и все твои построения рушатся, как карточный домик
    _>Ну так достаточно наличия хотя бы двух элементарных операций на одном шаге, чтобы продемонстрированная мною технология заработала.


    Ну вперед. Продемонстрируй. Пока что много слов и очень мало дела. Забудь про SendOrder. Заказ поднимается из базы данных и над ним надо совершить манипуляции, указанные в моем примере.

    M>>Я умолчу, что краткое описание «всего лишь» SendOrder — это почти 100 пунктов, многие из которых не элементарны.

    _>Ты же вроде сам писал, что SendOrder — это всего лишь sent=true и потом сохранения ордера в базу. Так где истина то у тебя? )

    Понимаешь, вы тут скопом не смогли осилить даже маленькую задачу. Зачем вам надо знать, что делает SendOrder? Вам достаточно знать, что мой пример с SendOrder'ом не связан никак. То есть заказ отправлен и положен в базу. Неделю спустя надо изменить сумму заказа.

    В примере нигде нет про send_order. Я не знаю, почему вы все так настырно его выдумываете


    _>>>Тебе продемонстрировали возможности перевода части проверок в статику (а это очень круто по целому ряду причин), причём для сложных алгоритмов. А тебе то хочется совсем другого, более простого — некой помощи в организации сложных рантайм проверок

    M>>Стоп. Вот у меня есть «сложная рантайм проверка». Ее никто не осилил. Но я должен поверить, ага-ага, что будет «некая помощь» в «сложных рантайм проверках» в «нетривиальных примерах».
    M>>

    _>Ты как-то криво читаешь мой текст.


    Я читаю ровно то, что ты пишешь

    _>Здесь под сложностью/простотой задачи подразумевается не размер твоего алгоритма, а то, что мы хотим с ним сделать. Перевести часть его во время компиляции — это сложная задача (вне зависимости от количества проверок). Которая не всегда реализуема (во всяком случае целиком), но приносящая много бонусов в случае успеха. Однако демонстрация этого тебя абсолютно не впечатляет


    Потому что мне никто так ничего внятно и не продемонстрировал. Я увижу, наконец, до конца реализованный пример, или все будет так и скатываться в демагогию про «приношение многия бонусов»?

    _>, просто потому, что тебе хочется видоизменить свой алгоритм в совсем другом направление — просто несколько упорядочить его (чтобы не было пропущенных рантайм проверок например), а количество рантайм проверок не важно. Это очевидно задача другого класса, гораздо более простая, выполнимая и скорее относящаяся к культуре проектирования. Другое дело, что не факт что статическая типизация будет иметь какое-то отношения к этому. Хотя не знаю, может и с помощью неё есть какие-то решения. Я не готов с ходу ответить, т.к. не обдумывал ещё данное направление.


    M>>Пожалуйста. Вот тебе «менее тривиальный» пример
    Автор: Mamut
    Дата: 06.02.15
    . Я могу специально для тебя выложить flow нашей функции SendOrder. Да ты и другие пропоненты стат. типизации же просто загнутся решать «организацию сложных рантайм проверок».


    _>Вообще то это тривиально реализуется даже прямо на том моём простейшем примере.


    Вперед. Реализуй это тривиально.

    _>Потому как у тебя тут не появляется никаких новых состояний (всё тоже самое — можно менять сумму или нельзя). А количество условий для перехода между состояниями вообще не принципиально. Оно же всё равно записывается тем же самым тупым кодом в лоб (без всяких игр с типами), прямо как и у тебя. Просто там в итоге будет не true/false, а тип такой или тип другой.


    Какой тип? Я увижу когда-нибудь полноценный код?


    _>Однако это я опять же о своём, об интересной задачке переноса вычислений в статику. А тебе то это не интересно, тебе то хочется как-то уменьшить число ошибок в том самом тупом коде рантайм проверки этого множества условий...



    То есть ты хочешь поговорить о сфероваккумных конях. Это мне неинтересно.

    _>>>Возможно есть какие-то варианты со статическом анализом операций (тогда типами будут уже не ордера, а операции), но так с ходу не придумывается. )))

    M>>Я и заметил, что «с ходу не придумывается». Причем ни у кого. А пафоса-то! А громких заявлений!

    _>Ну я вроде как ничего не заявлял))) Я только показал пример, демонстрирующий перевод части рантайм проверок во время компиляции. Причём не на каком-то своём удобном примере, а на совсем неудобном твоём, показав что и там такое возможно.


    Об боже? Неужели это возможно? Да ты что? И дальше что?
    — Как это можно использовать?
    — Где это можно использовать?
    — Нетеоретические примеры сложнее hello world'а


    _>В начале мне показалась что цель именно в этом (т.к. она более нетривиальная и интересная). Теперь я вижу, что тебя интересовало другое и для твое проблемы (не задачки, а того, что надо с ней сделать!)



    Ты не поверишь, но меня ни на грамм не интересуют сугубо теоретические проблемы. Мне платят не за то, что я сижу целыми днями, придумывая, как прекрасно решаются сферовакуумные кони. Я пока что вижу сплошной пафос, громкие заявления и сугубые теоретизирования

    И это — при том, что все началось с презентации
    Автор: jazzer
    Дата: 30.01.15
    про банк. Только я привожу классическую банковскую задачу (прикинь, я сам работаю в банке), как начинается «ой, это не такая задача, как нам нравится»


    dmitriid.comGitHubLinkedIn
    Re[10]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 07.03.15 06:56
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    EP>В аффинном пространстве есть точки и векторы. Складывать две точки нельзя, разница двух точек это вектор, сумма точки и вектора — точка, линейная комбинация векторов — вектор. Статическая типизация, помимо всего прочего, позволяет закодировать эту логику и проверять её во время компиляции.


    Не совсем ясно, зачем тебе именно афинное пространство. Ты подаёшь это как абсолютное добро. Все что нужно для вычислений — точка отсчета, вектор, матрица + кое какие оптимизации.

    Это позволяет упросить вычислительную модель. С другой стороны, если количество депенденсов будет конское, вполне возможно будет сложно контролировать типы и будет проще задавать точку как точкой, а не вектором.

    То есть, нужен баланс — не просто "типизация это круто", а смотреть количество депенденсов. Если зависимостей единицы, то в статической типизации смысла большого нет.
    Re[11]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 07.03.15 08:27
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    EP>>В аффинном пространстве есть точки и векторы. Складывать две точки нельзя, разница двух точек это вектор, сумма точки и вектора — точка, линейная комбинация векторов — вектор. Статическая типизация, помимо всего прочего, позволяет закодировать эту логику и проверять её во время компиляции.

    I>Не совсем ясно, зачем тебе именно афинное пространство. Ты подаёшь это как абсолютное добро.

    Натуральной точки отсчёта может и не быть для конкретной задачи — это собственно и есть аффинное пространство.
    Например std::chrono — сложение двух time_point не имеет смысла, и это кодируется в системе типов: http://en.cppreference.com/w/cpp/chrono/time_point/operator_arith2

    I>Все что нужно для вычислений — точка отсчета, вектор, матрица + кое какие оптимизации.


    Для вычислений не нужны даже отдельные типы для матриц/векторов, достаточно везде использовать double*. Не говоря уже о том, что вычисления можно проводить вообще без статической типизации
    Или чуть менее радикальный пример — в моих задачах часто известны размерности матриц/векторов в compile-time, кодирование этой информации в типах позволяет отлавливать ошибки связанные с размерностью на этапе компиляции.

    I>Это позволяет упросить вычислительную модель.


    Вообще-то обсуждается проверка части логики задачи статической типизацией — аффинное пространство в std::chrono как раз тому пример.

    I>С другой стороны, если количество депенденсов будет конское, вполне возможно будет сложно контролировать типы и будет проще задавать точку как точкой, а не вектором.


    Каких "депенденсов"?

    I>То есть, нужен баланс — не просто "типизация это круто", а смотреть количество депенденсов. Если зависимостей единицы, то в статической типизации смысла большого нет.


    Согласен, везде нужен баланс — для некоторых задач и язык с динамической типизацией более целесообразен. Но речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности
    Re[12]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 07.03.15 18:16
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    I>>Не совсем ясно, зачем тебе именно афинное пространство. Ты подаёшь это как абсолютное добро.


    EP>Натуральной точки отсчёта может и не быть для конкретной задачи — это собственно и есть аффинное пространство.


    Приведи пример реальной задачи, которая наилучшим образом решается через афинное пространство. Я yt спрашиваю, можно ли его реализовать в С++, я спрашиваю где это применяется. Т.е. интересует область, где в наличии профит афинного над векторным.


    EP>Согласен, везде нужен баланс — для некоторых задач и язык с динамической типизацией более целесообразен. Но речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности


    То есть, смысл не интересует, так и запишем
    Re[13]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 09.03.15 12:55
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    I>>>Не совсем ясно, зачем тебе именно афинное пространство. Ты подаёшь это как абсолютное добро.

    EP>>Натуральной точки отсчёта может и не быть для конкретной задачи — это собственно и есть аффинное пространство.
    I>Приведи пример реальной задачи, которая наилучшим образом решается через афинное пространство. Я yt спрашиваю, можно ли его реализовать в С++, я спрашиваю где это применяется. Т.е. интересует область, где в наличии профит афинного над векторным.

    Работа со временем — например std::chrono. Указатели/Итераторы (std::ptrdiff_t, std::iterator_traits::difference_type). Обработка CAD моделей.

    EP>>Согласен, везде нужен баланс — для некоторых задач и язык с динамической типизацией более целесообразен. Но речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности

    I>То есть, смысл не интересует, так и запишем

    Как ты сделал такой вывод?
    Re[14]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 09.03.15 13:28
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    EP>>>Натуральной точки отсчёта может и не быть для конкретной задачи — это собственно и есть аффинное пространство.

    I>>Приведи пример реальной задачи, которая наилучшим образом решается через афинное пространство. Я yt спрашиваю, можно ли его реализовать в С++, я спрашиваю где это применяется. Т.е. интересует область, где в наличии профит афинного над векторным.

    EP>Работа со временем — например std::chrono. Указатели/Итераторы (std::ptrdiff_t, std::iterator_traits::difference_type). Обработка CAD моделей.


    Опять ни о чем. Я просил тебя показать пример использования. "обработка CAD моделей" — здесь я сам могу тебе столько рассказать, что не унесёшь.
    Chrono — это библиотечная вещь. Тебе нужно показать вещь, где она применяется и применение дает больше профита, нежели другая реализация.

    EP>>>Согласен, везде нужен баланс — для некоторых задач и язык с динамической типизацией более целесообразен. Но речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности

    I>>То есть, смысл не интересует, так и запишем

    EP>Как ты сделал такой вывод?


    Из суммы двух слагаемых —
    1 речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности
    2 ты не показал никакого внятного примера,т.е. все заканчивается на принципиальных возможностях
    Re[15]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 09.03.15 13:53
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    I>>>Приведи пример реальной задачи, которая наилучшим образом решается через афинное пространство. Я yt спрашиваю, можно ли его реализовать в С++, я спрашиваю где это применяется. Т.е. интересует область, где в наличии профит афинного над векторным.

    EP>>Работа со временем — например std::chrono. Указатели/Итераторы (std::ptrdiff_t, std::iterator_traits::difference_type). Обработка CAD моделей.
    I>Опять ни о чем. Я просил тебя показать пример использования.

    Пример использования чего? Указателей? Итераторов? std::chrono? Прикалываешься

    I>"обработка CAD моделей" — здесь я сам могу тебе столько рассказать, что не унесёшь.


    Да, да, я всё помню, ты сначала пел про то что в одиночку перекодил 40 программистов на задачах линейной алгебры, а потом конечно же подтвердил это знаниями о NaN'ах
    Автор: Ikemefula
    Дата: 24.09.13
    . Ещё помню как виртуозно ты вычислял сложность вставки в вектор
    Автор: Evgeny.Panasyuk
    Дата: 21.10.13
    .
    Так что можешь не стараться, мне не интересно

    I>Chrono — это библиотечная вещь. Тебе нужно показать вещь, где она применяется и применение дает больше профита, нежели другая реализация.


    Профит в том, что:
    1. Часть логических ошибок ловится в compile-time
    2. Часть ошибок в перестановках аргументов ловится в compile-time.
    3. При описании API нужно меньше документации (меньше мест ошибиться или забыть исправить при рефакторинге) — если в интерфейсе стоит Duration, то сразу ясно что это длительность.
    4. Открываются дополнительные возможности перегрузки, и как следствие более удобное API.

    I>>>То есть, смысл не интересует, так и запишем

    EP>>Как ты сделал такой вывод?
    I>Из суммы двух слагаемых —
    I>1 речь идёт не о "нужно/не нужно/где и в каких пропорциях", а о принципиальной возможности
    I>2 ты не показал никакого внятного примера,т.е. все заканчивается на принципиальных возможностях

    Допустим даже 2. верно, всё равно не сходится
    Re[16]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 09.03.15 15:21
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    I>>Опять ни о чем. Я просил тебя показать пример использования.


    EP>Пример использования чего? Указателей? Итераторов? std::chrono? Прикалываешься


    А что тебя смущает ? Ты утверждаешь, ни много ни мало, что есть некоторая предметная область, в которой задачи имеет смысл решать с использованием афинного пространства, а не векторного.
    Хочется подтверждений.

    I>>"обработка CAD моделей" — здесь я сам могу тебе столько рассказать, что не унесёшь.


    EP>Да, да, я всё помню, ты сначала пел про то что в одиночку перекодил 40 программистов на задачах линейной алгебры, а потом конечно же подтвердил это


    Вообще говоря ты привел свои догадки пополам с вымыслом. Нет и не было задачи `перекодить` 40 человек.

    >знаниями о NaN'ах
    Автор: Ikemefula
    Дата: 24.09.13
    .


    Ты свою ссылку открывал ? Там про NaN в JS, а не про линейную алгебру. Срыватели покровов такие срыватели

    I>>Chrono — это библиотечная вещь. Тебе нужно показать вещь, где она применяется и применение дает больше профита, нежели другая реализация.


    EP>Профит в том, что:


    Покажи внятный пример использования. Профит есть и у векторного пространства. Твоя задача — показать область, где у афинного профит над векторным.
    Пока что ты смог указать chrono.К твоему сведению это не предметная область, а либа.
    Чисто логика — косточка от арбуза не является арбузом. Более того, арбуз имеет смысл есть без косточек
    Re[17]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 09.03.15 17:24
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    I>>>Опять ни о чем. Я просил тебя показать пример использования.

    EP>>Пример использования чего? Указателей? Итераторов? std::chrono? Прикалываешься
    I>А что тебя смущает ?

    То что примеры итерации или точек времени очевидны. И я думаю ты их (или нечто подобное) уж точно использовал при решении реальных задач.

    EP>>Да, да, я всё помню, ты сначала пел про то что в одиночку перекодил 40 программистов на задачах линейной алгебры, а потом конечно же подтвердил это

    I>Вообще говоря ты привел свои догадки пополам с вымыслом. Нет и не было задачи `перекодить` 40 человек.

    Тем не менее, ты зачем-то этим хвастался

    I>>>Chrono — это библиотечная вещь. Тебе нужно показать вещь, где она применяется и применение дает больше профита, нежели другая реализация.

    EP>>Профит в том, что:
    I>Покажи внятный пример использования.

    auto start = system_clock::now();
    calc();
    auto end = system_clock::now();
    auto diff = end - start; // OK
    auto x = start + end; // Compile error
    auto y = diff + 5s + 5min; // OK
    auto z = start + 2h + 2s + diff; // OK


    I>Профит есть и у векторного пространства. Твоя задача — показать область, где у афинного профит над векторным.

    I>Пока что ты смог указать chrono.К твоему сведению это не предметная область, а либа.
    I>Чисто логика — косточка от арбуза не является арбузом. Более того, арбуз имеет смысл есть без косточек

    Я был убеждён в том, что предметная область применения библиотеки std::chrono очевидна
    Re[19]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 09.03.15 21:49
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    EP>>То что примеры итерации или точек времени очевидны.

    I>Да, когда нечего сказать, в ход идет аргумент "тут всё просто", "это очевидно"

    Ты действительно никогда не использовал итераторы?
    template<typename I, typename P>
    I partition_point_m(I first, I last, P p)
    {
        while(first != last)
        {
            I middle = first + (last - first)/2;
            //I middle = (last - first)/2; - Compile error
            if( p(*middle) )
                last = middle;
            else
                first = ++middle;
        }
        return first;
    }


    I>>>Покажи внятный пример использования.

    EP>>
    EP>>auto start = system_clock::now();
    EP>>

    I>Итого — примера нет.

    Почему?

    EP>>Я был убеждён в том, что предметная область применения библиотеки std::chrono очевидна

    I>Попробуй выразить эту очевидность в терминах пользователя, сразу станет ясно. Вот скажем, редактор векторной графики — здесь всё предельно понятно.

    Что именно понятно?

    I>Попробуй придумать такой же пример,


    Какой такой же? Что конкретно показывает твой пример "редактор векторной графики"?

    I>только что бы демонстрировал профит от chrono


    Boost.Asio подойдёт? http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/system_timer.html#boost_asio.reference.system_timer.examples

    I>и сформулируй, почему именно от chrono будет максимум профита.


    Смотри четыре пункта выше.
    Re[20]: Про типы и логику
    От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
    Дата: 10.03.15 06:51
    Оценка:
    Здравствуйте, Evgeny.Panasyuk, Вы писали:

    EP>Ты действительно никогда не использовал итераторы?


    А ты бросил пить ?

    I>>Итого — примера нет.


    EP>Почему?


    Потому что надо назвать внятно область применения.

    EP>>>Я был убеждён в том, что предметная область применения библиотеки std::chrono очевидна

    I>>Попробуй выразить эту очевидность в терминах пользователя, сразу станет ясно. Вот скажем, редактор векторной графики — здесь всё предельно понятно.

    EP>Что именно понятно?


    Область.

    I>>Попробуй придумать такой же пример,


    EP>Какой такой же? Что конкретно показывает твой пример "редактор векторной графики"?


    Показывает, где и как будет применяться либа для векторных операций всяких. Там же, кстати, применяется и афинное пространство. Если хочешь, можешь попробовать на этом примере объяснить, за счет чего афинное пространство зарулит векторное.

    I>>только что бы демонстрировал профит от chrono


    EP>Boost.Asio подойдёт? http://www.boost.org/doc/libs/1_57_0/doc/html/boost_asio/reference/system_timer.html#boost_asio.reference.system_timer.examples


    Разумеется, нет. Это еще одно название, а тебя просили область применения.

    I>>и сформулируй, почему именно от chrono будет максимум профита.


    EP>Смотри четыре пункта выше.


    Можно подумать у метода с векторным пространством нет преимуществ, а у афинного нет недостатков, ога.
    Re[21]: Про типы и логику
    От: Evgeny.Panasyuk Россия  
    Дата: 10.03.15 14:48
    Оценка:
    Здравствуйте, Ikemefula, Вы писали:

    EP>>Ты действительно никогда не использовал итераторы?

    I>А ты бросил пить ?

    Ты чего пример partition_point удалил? Потому что области применения двоичного поиска очевидны, да?

    I>>>Попробуй придумать такой же пример,

    EP>>Какой такой же? Что конкретно показывает твой пример "редактор векторной графики"?
    I>Показывает, где и как будет применяться либа для векторных операций всяких. Там же, кстати, применяется и афинное пространство. Если хочешь, можешь попробовать на этом примере объяснить, за счет чего афинное пространство зарулит векторное.

    Уже объяснял. Разжёвывать не собираюсь, ибо интересуешься ты не в познавательных целях, а чисто ради упражнения в демагогии/троллинге

    EP>>Смотри четыре пункта выше.

    I>Можно подумать у метода с векторным пространством нет преимуществ

    Я этого не говорил.
    Re[8]: Ах да, мое решение :)
    От: Evgeny.Panasyuk Россия  
    Дата: 09.04.15 18:29
    Оценка:
    EP>>>Вот твой изначальный пример:
    EP>>>это можно трактовать как "можно уменьшать и увеличивать сумму заказа" — это функция change_amount, у которой есть предусловие "заказ не помечен как отправленный", которая безусловно изменяет сумму. Тебе как раз и показывали примеры форсирующие это предусловие в compile-time:
    M>>Я перенес это «предусловие» внутрь функции change_amount.
    EP>Нарушение предусловия это баг в программе, программа находится в том состоянии в котором не должна была по логике вещей, и как она туда попала неизвестно, лучше всего пристрелить такую программу как взбесившуюся собаку. Почитай наконец что такое precondition.
    EP>Предусловия можно проверять, и как-то энфорсить, но отнюдь не обязательно. Например assert'ы энфорсящие предусловия часто используют только в отладочных режимах.
    EP>Система типов позволяет энфорсить некоторые предусловия в compile-time, но не все. Я даже больше скажу, далеко не все предусловия можно проверить в runtime — попытка такой проверки попросту может поломать инварианты, и сделать невозможным достижение постусловий.

    Кстати, вот выступление John Lakos из Bloomberg по поводу предусловий, assert'ов и defensive programming: "Defensive Programming Done Right"
    http://www.youtube.com/watch?v=1QhtXRMp3Hg
    http://www.youtube.com/watch?v=tz2khnjnUx8
    Re[9]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 10.04.15 13:29
    Оценка:
    EP>Кстати, вот выступление John Lakos из Bloomberg по поводу предусловий, assert'ов и defensive programming: "Defensive Programming Done Right"

    Я из другого лагеря

    3.13 Do not program "defensively"

    A defensive program is one where the programmer does not "trust" the input data to the part of the system they are programming. In general one should not test input data to functions for correctness. Most of the code in the system should be written with the assumption that the input data to the function in question is correct. Only a small part of the code should actually perform any checking of the data. This is usually done when data "enters" the system for the first time, once data has been checked as it enters the system it should thereafter be assumed correct.

    ...
    The caller is responsible for supplying correct input.




    dmitriid.comGitHubLinkedIn
    Re[10]: Ах да, мое решение :)
    От: Evgeny.Panasyuk Россия  
    Дата: 10.04.15 14:35
    Оценка:
    Здравствуйте, Mamut, Вы писали:

    EP>>Кстати, вот выступление John Lakos из Bloomberg по поводу предусловий, assert'ов и defensive programming: "Defensive Programming Done Right"

    M>Я из другого лагеря

    1. Ну то есть видео ты не смотрел, зато мнение имеешь
    2. То есть у тебя всё-таки есть интуитивное понимание того что такое предусловие, и что предусловие не предполагает проверку этого условия внутри функции — но тем не менее обычные внутренние условия функции ты называешь предусловиями
    Отредактировано 10.04.2015 14:37 Evgeny.Panasyuk . Предыдущая версия .
    Re[11]: Ах да, мое решение :)
    От: Mamut Швеция http://dmitriid.com
    Дата: 12.04.15 07:33
    Оценка:
    EP>>>Кстати, вот выступление John Lakos из Bloomberg по поводу предусловий, assert'ов и defensive programming: "Defensive Programming Done Right"
    M>>Я из другого лагеря

    EP>1. Ну то есть видео ты не смотрел, зато мнение имеешь


    Я его еще не посмотрел (не было времени), поэтому и смайлик


    EP>2. То есть у тебя всё-таки есть интуитивное понимание того что такое предусловие, и что предусловие не предполагает проверку этого условия внутри функции — но тем не менее обычные внутренние условия функции ты называешь предусловиями


    У меня есть объективное понимание того, что такое предусловие, а так же объективное понимание, что ты сам не понимаешь, о чем говоришь. Я тебе это даже на пальцах показал тут
    Автор: Mamut
    Дата: 05.03.15


    dmitriid.comGitHubLinkedIn
    Re[10]: Про типы и логику
    От: Sinclair Россия https://github.com/evilguest/
    Дата: 14.04.15 09:40
    Оценка:
    Здравствуйте, alex_public, Вы писали:
    _>Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?
    Это не он ограничивает, это реальность прикладной области. Если не делать сохранение в БД между элементарными операциями, то первый же fault приведёт к разнообразным и интересным результатам после рестарта. Мало кто ожидает, скажем, многократного списания денег со счёта из-за того, что длинная транзакция была прервана на полпути.
    Уйдемте отсюда, Румата! У вас слишком богатые погреба.
    Re[11]: Про типы и логику
    От: alex_public  
    Дата: 14.04.15 11:36
    Оценка:
    Здравствуйте, Sinclair, Вы писали:

    _>>Т.е. ты ограничиваешь свою задачу строго одной элементарной операцией на шаг (загрузка/сохранение БД)?

    S>Это не он ограничивает, это реальность прикладной области. Если не делать сохранение в БД между элементарными операциями, то первый же fault приведёт к разнообразным и интересным результатам после рестарта. Мало кто ожидает, скажем, многократного списания денег со счёта из-за того, что длинная транзакция была прервана на полпути.

    Так я же не спорю, а как раз наоборот выясняю детали его задачи. Ну отлично, если строго одна элементарная операция на транзакцию, то я особого смысла в программирование на типах тут не вижу.

    P.S. Да, кстати, а мне казалось, что как раз использование транзакций (которые в БД) и позволяет не беспокоиться о проблемах при сбоях посередине длинной последовательности операций. Ну да ладно...
    Re[13]: Про типы и логику
    От: alex_public  
    Дата: 14.04.15 13:45
    Оценка:
    Здравствуйте, Sinclair, Вы писали:

    S>Так и в обработке ордеров: то, что обработка заказа — это не один метод с множеством ветвлений, а множество вызовов множества методов, никак не отменяет наличия интересных инвариантов, которые хочется контролировать статически.


    В таком случае надо придумать какой-то контекст, в котором "хранились" бы инварианты. А с учётом того, что при таком раскладе эти инварианты теоретически должны переживать перезапуск приложения, очень сомнительно, что это можно реализовать через типы.
    Re[10]: Ах да, мое решение :)
    От: diez_p  
    Дата: 17.04.15 15:39
    Оценка:
    Здравствуйте, Mamut, Вы писали:


    EP>>Кстати, вот выступление John Lakos из Bloomberg по поводу предусловий, assert'ов и defensive programming: "Defensive Programming Done Right"


    M>Я из другого лагеря


    M>

    M>3.13 Do not program "defensively"

    M>A defensive program is one where the programmer does not "trust" the input data to the part of the system they are programming. In general one should not test input data to functions for correctness. Most of the code in the system should be written with the assumption that the input data to the function in question is correct. Only a small part of the code should actually perform any checking of the data. This is usually done when data "enters" the system for the first time, once data has been checked as it enters the system it should thereafter be assumed correct.

    M>...
    M>The caller is responsible for supplying correct input.


    Данные монолитом не проходят по системе, и там где с 0 можно складывать, делить на 0 нельзя. Именно по этому каждому типу необходимо выполнять проверку того с чем он работает. Это касается ентерпрайза, в остальных областях такой метод может повлечь вычислительный оверхед, который не приемлим.
     
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.