Re[70]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 04.03.15 09:07
Оценка:
Здравствуйте, jazzer, Вы писали:

J>PROF_IF — это рантайм-проверка и есть.

Вот именно. Т.е. мы так никуда и не ушли от рантайм-проверок. А значит, всё, что мы делаем в рантайме — бесполезно.
Это как иметь нормальные numeric типы в выражениях, но все переменные имеют тип object. И мы каждый раз приводим: object a = (int)b*(int)c.

J>Какие именно?

Компайл-тайм верификацию корректности кода и отсуствие "неожиданных сообщений об ошибках".

J>ЗЫ Мне вообще удивительно, в одних постах ты пишешь так, что выглядит, будто ты все понял (правда, эти посты обычно Мамуту адресованы), а в других, типа этого — как будто все мимо.

Это оттого, что вместо ответов на вопросы вы пытаетесь угадать, "понял" я или нет.
Дело не в этом. Я "теоретическую" часть понимаю не хуже вас с ARK. Я задаю совершенно конкретные вопросы, которых вы избегаете. Или начинаете нести откровенный бред, утверждая, к примеру, что MessageBox показанный изнутри increase_amount чем-то хуже, чем такой же MessageBox, показанный изнутри try_increasing_amount().
Ну, то есть может быть это и не бред, но в инженерной дискуссии принято обосновывать утверждения, а не просто говорить "вот этого MessageBox пользователь ожидает, а этого — нет!".

J>ЗЗЫ Сайту ощутимо не хватает фичи "упоминаний". В смысле, если где-то твой ник упомянули — ты мог прийти и отписаться. А то я чудом на этот пост попал.

Это совершенно необязательно — я отвечаю на все ваши реплики, стоящие того. И если я где-то пишу, что вы мне не ответили — значит, вы не ответили мне на пост, в котором я отвечал вам.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[74]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 04.03.15 09:21
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну вот тем не менее мы так и не увидели примера кода, в котором

S>а) есть загрузка ордера из базы

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

S>б) нет функции обработки, которая бросает runtime ошибку для "статически-верифицируемых" свойств.


Нет никаких "статически-верифицируемых" свойств (хотя хз, что ты под этим имеешь в виду, конечно). Есть гарантии со стороны компилятора, что определенные функции могут быть позваны только в определенных местах кода, и эти места определяются рантайм-свойствами. Всё. А обработка рантайм-ошибок точно такая же, как всегда — исключения, коды ошибок и прочая, тут вообще ничего не меняется.
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[70]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 04.03.15 09:36
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


J>>Я же показал, чем тебя не устраивает try_to_change_amount?

S>Вы что, шутите?
S>Ок, давайте внимательно посмотрим на ваш try_to_change_amount:
S>
S>void try_to_change_amount(Order& o)
S>{
S>  PROP_IF(o, has_risk(o), HasRisk) { // что это мы тут имеем? А! Это же... РАНТАЙМ ПРОВЕРКА!!! Которых у вас якобы нету!

можно пальцем показать, где я говорил, что их нету? когда в моем же примере кода они есть? :???:

S>    // а тут??? Мы что, тупо проигнорировали команду - и типа делаем вид, что всё нормально??? 
S>    // на самом деле тут, конечно же, будет throw - потому что ничего больше сделать нельзя.

конечно же, тут будет throw :xz: Или msg box :xz: Или сообщение по сети :xz:
я разве где-то говорил, что этого не будет :???:

S>  }
S>  PROP_ELSE(o) {
S>    increase_amount(o, 2.71);
S>  };
S>}
S>

J>>Где она падает, сорри? У меня такое чувство, что мы говорим о разных вещах.
S>См. код выше. Вы ловко замели проблему "попытка увеличить amount для рискового ордера" под ковёр, ничего не скажешь. Просто сделаем вид, что такой попытки не было.

S>Вашему двухслойному коду вполне эквивалентен вот такой:

S>
S>increase_amount(Order& o, Money amt)
S>{
S>  if(o.HasRisk)
S>  {  // doing nothing 
S>  }
S>  else
S>  {
S>    o.Amount += amt;
S>  }
S>}
S>


Он не эквивалентен в смысле возможности написать ошибочный код. У тебя увеличить amount по ошибке можно в обоих етках и вообще за пределами ифа. У меня нет. Именно в этом разница.
Блин, ну ты же сам писал: "Код, содержащий незаконный переход, просто не скомпилируется."
Вот что в твоем коде может быть:
S>
S>increase_amount(Order& o, Money amt)
S>{
    o.Amount += amt; // незаконно! но компилируется!
S>  if(o.HasRisk)
S>  {  // doing nothing 
      o.Amount += amt; // незаконно! но компилируется!
S>  }
S>  else
S>  {
S>    o.Amount += amt;
S>  }
    o.Amount += amt; // незаконно! но компилируется!
S>}
S>

А в моем всего этого быть не может в принципе.
Потому что, как ты правильно выразился, у меня код двухслойный: есть слой функций, выполняющих реальные действия (типа increase_amount), есть слой функций бизнес-логики (типа try_to_change_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[71]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 04.03.15 11:05
Оценка: 3 (1)
Здравствуйте, Sinclair, Вы писали:

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


J>>PROF_IF — это рантайм-проверка и есть.

S>Вот именно. Т.е. мы так никуда и не ушли от рантайм-проверок.
Я где-то говорил, что мы от них ушли?

S>А значит, всё, что мы делаем в рантайме — бесполезно.

Не понял.

S>Это как иметь нормальные numeric типы в выражениях, но все переменные имеют тип object. И мы каждый раз приводим: object a = (int)b*(int)c.

Нет, не так.
Твой код:
object operator*(object a, object b)
{
  if (type(a)!=int) throw "первый параметр в сложении плохой";
  if (type(b)!=int) throw "второй параметр в сложении плохой";
  return (int)a * (int)b;
}

operator=(object a, object b)
{
  if (type(a)!=int) throw "первый параметр в присваивании плохой";
  if (type(b)!=int) throw "второй параметр в присваивании плохой";
  (int)a = (int)b;
}

f(object a, object b, object c) {
  a=b*c; // красота, всё чистенько
}

мой код:
int operator*(int a, int b)
{
  return a*b;
}
operator=(int a, int b)
{
  return a=b;
}

f(object a, object b, object c) {
  if (type(a)!=int) throw "По сети пришла фигня";
  int ia = (int)a;
  if (type(b)!=int) throw "Вы в поле в форме ввели фигню";
  int ib = (int)b;
  if (type(c)!=int) throw "В файле лежит фигня";
  int ic = (int)c;

  // дальше исключений не будет
  ia = ib*ic;
}

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

J>>Какие именно?

S>Компайл-тайм верификацию корректности кода и отсуствие "неожиданных сообщений об ошибках".

J>>ЗЫ Мне вообще удивительно, в одних постах ты пишешь так, что выглядит, будто ты все понял (правда, эти посты обычно Мамуту адресованы), а в других, типа этого — как будто все мимо.

S>Это оттого, что вместо ответов на вопросы вы пытаетесь угадать, "понял" я или нет.
S>Дело не в этом. Я "теоретическую" часть понимаю не хуже вас с ARK. Я задаю совершенно конкретные вопросы, которых вы избегаете. Или начинаете нести откровенный бред, утверждая, к примеру, что MessageBox показанный изнутри increase_amount чем-то хуже, чем такой же MessageBox, показанный изнутри try_increasing_amount().
??? Это ты о чем?

S>Ну, то есть может быть это и не бред, но в инженерной дискуссии принято обосновывать утверждения, а не просто говорить "вот этого MessageBox пользователь ожидает, а этого — нет!".

Ты точно со мной разговариваешь?

J>>ЗЗЫ Сайту ощутимо не хватает фичи "упоминаний". В смысле, если где-то твой ник упомянули — ты мог прийти и отписаться. А то я чудом на этот пост попал.

S>Это совершенно необязательно — я отвечаю на все ваши реплики, стоящие того. И если я где-то пишу, что вы мне не ответили — значит, вы не ответили мне на пост, в котором я отвечал вам.
Тем не менее, я хотел бы, чтобы было упоминание о посте, в котором меня склоняют без моего ведома. Чтоб я мог хотя бы зашититься, если там вдруг обвинят меня в том, чего я не говорил.

ЗЫ А почему вдруг на вы, если не секрет?
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[81]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 04.03.15 14:03
Оценка:
M>>Можно вместо тонны слов и «статьи, после слов надеюсь понятно» показать как это будет в коде?

J>имей совесть. Там есть пример кода, прямо в статье. Ты почему-то делаешь вид, что его там нет. Наверное, ты просто перепутал форум и решил, что мы в КСВ.


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


M>>Потому что написать «Надеюсь, идея понятна. Дополнительные требования навешиваются аналогично. Если элементарных свойств/требований становится слишком много, то можно их просто упаковать в мета-свойство IncreaseAmountOK» легко. Но почему-то никто так и не осилил больше одного шага

J>Там есть пример кода, прямо в статье.

Покажи мне, где там пример кода мета-свойства IncreaseAmountOK, и как его использовать.

Покажи мне пошагово, как и где твой код, реализующий шаг 1 легким движением руки превращается в код, реализующий шаг два (напомню: именно ты говорил о том, что типы позволяют легко справляться с ad-hoc изменениями). Почему у тебя все заканчивается строго и исключительно на «там дальше просто/очевидно/поянтно»?

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

M>>Я хочу увидеть это «метасвойство». Я хочу увидеть, как решается заявленное тобой «типы помогают при ad-hoc дизайне», ведь именно для этого в моей задаче три шага.

J>просто добавляешь дополнительные проверки внутри can_increase_amount.

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

M>>Потому что мне действительно хочется увидеть полное решение моей задачи, в котором используются все громогласные заявления, начиная отсюда
Автор: Klapaucius
Дата: 03.02.15
. Этот вопрос я уже задавал, но задам еще раз: почему все приводят короткие, неполные решения с заявлением «ну, дальше все понятно» и не могут осилить одно полное решение? Но после этого я должен поверить, что это все круто будет работать для гораздо более разветвленной
Автор: Mamut
Дата: 06.02.15
реальности?

J>просто добавляешь дополнительные проверки внутри can_increase_amount.

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

Почему никто не хочет привести полный код решения этого самого «просто добавь проверки»?

M>>Хех. Кстати. Перечитал свои условия для шага 1, и понял, что у тебя не реализован даже шаг 1

M>>Я умолчу о том, что все, как огня избегают отвечать на вопрос, а как все это тестировать

J>А как ты тестируешь, что у тебя в int i действительно int, а не строка? Ответ — никак. Это невозможно (если только ты не расстреливаешь память или в компиляторе не водятся баги), и тестировать это смысла нет.


Это не ответ на мой вопрос, а уход от вопроса.

M>>Но это отдельный вопрос (хотя он и был, по сути, в самом
Автор: Mamut
Дата: 03.02.15
начале
Автор: Mamut
Дата: 03.02.15
нашего уютного срачика).


J>Срачик у тебя получилось создать, спору нет, тут ты мастер.


Срачик создали вы сами


dmitriid.comGitHubLinkedIn
Re[72]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 04.03.15 14:07
Оценка:
J>будет проверяться каждый раз (тупо лишняя работа) и исключения будут вылетать из глубины операторов, а не из функции бизнес-логики f. Плюс у меня эти исключения будут осмысленными, так как они на уровне бизнес-логики генерятся и имеют бизнес-смысл (типа "вы вот тут ввели строчку, а надо число"), а у тебя будет просто "не могу сложить вот это и вот это" — при том что пользователь может и понятия не иметь, что там что-то где-то в недрах складывается, и уж тем более не будет знать, что за "вот это" имеется в виду.


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

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


dmitriid.comGitHubLinkedIn
Re[74]: Haskell нужен! (в Standard Chartered Bank)
От: alex_public  
Дата: 04.03.15 15:51
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну вот тем не менее мы так и не увидели примера кода, в котором

S>а) есть загрузка ордера из базы
S>б) нет функции обработки, которая бросает runtime ошибку для "статически-верифицируемых" свойств.

А чем тебе этот http://rsdn.ru/forum/philosophy/5971692.1
Автор: alex_public
Дата: 03.03.15
пример не подходит? ) Там не просто есть обе требуемые тобой вещи, но это даже полный компилируемый код. )))
Re[81]: Haskell нужен! (в Standard Chartered Bank)
От: Evgeny.Panasyuk Россия  
Дата: 04.03.15 23:22
Оценка:
Здравствуйте, Mamut, Вы писали:

EP>1. Y может использоваться из разных мест.

EP>2. В разных контекстах проверки могут иметь разную форму, работать с разными наборами данных, хотя по сути будут проверять одно и тоже свойстов/предусловие. И далеко не все эти проверки можно собрать в одной функции X.
EP>3. Далеко не всегда проверки можно вызывать несколько раз подряд — это может поломать инварианты/постусловия. Чтобы вызывать Y несколько раз, придётся вызывать несколько раз X, что приведёт к повторным проверкам.
EP>4. И наконец, далеко не всегда предусловия можно проверить — даже однократная проверка может поломать инварианты/постусловия, либо вообще может быть невозможна физически.
M>Может. Возможно. Может. Возможно. Это мы уже проходили
Автор: Mamut
Дата: 26.02.15
:


Тебя удивляет наличие условий для целесообразного применения какой-то техники?

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


В очередной раз: в том что ранее недопустимое значение, стало вполне штатным режимом работы.

EP>>>>Как-то: вместо безликих amount'ов введи тип MoneyUSD или что там у вас

M>>>1. Нахер надо?
EP>>Догадайся:
EP>>

M>Я предлагаю хотя бы как-то

M>Я догадался: шобы було. Просто шобы було.

И?

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

Ты предложил "как-то", я показал — что не устраивает?

EP>>Например предотвратит передачу MoneyAUD в MoneyUSD, или например радикально сократит количество перестановок аргументов валидных с точки зрения типов

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

Есть:
void foo(X, X, X, X);
// ...
foo(a, b, c, d);
Код скомпилируется с любой из 24 перестановок аргументов a,b,c,d. А для
void bar(X, X, X, Y);
// ...
bar(a, b, c, d);
есть только 6 перестановок аргументов которые скомпилируются.

M>>>>>Передаем проверку на отсортированность/сортировку в одно место — и оппа «это становится бессмысленно» ©™

EP>>>>Каким образом? Типа assert(x is Sorted)? Так я об этом уже говорил:
M>>>Вау. Каким образом в стат. типизации будет проверено, что массив отсортированный? Магическим способом и святым духом?
EP>>Sorted это тип.
M>И что? Перечитай еще раз выделенное. Я просто использую твою логику. Убираем «предусловия». Переносим проверку в одну функцию, и все «это становится бессмысленно» ©

Ещё раз уточняю, какую конкретно проверку? assert(x is SortedTYPE) или assert(check_sorted(x))(то есть линейная проверка на отсортированность)?

EP>>Но какие из преимуществ динамического языка тогда останутся?

M>Вопрос должен быть поставлен наоборот: какие из преимуществ стат. языка останутся?

Почему наоборот-то? Ты предлагаешь в динамическом языке делать все runtime проверки, которые в статическом языке делаются в compile-time. При этом у тебя даже нет гарантии что эти runtime проверки поймают баг во время unit-test'ов.
То есть ты потратил сравнимые усилия (я бы сказал даже большие), получив при этом меньший результат, при этом потеряв скорость разработки (которую часто называют одним из главных плюсов динамических языков).
Ещё раз, какие из преимуществ динамического языка тогда останутся?

M>>>Потому что даже отсутсвие такого инструмента приводит к двум ошибкам в год.

EP>>Найденным?
M>А только они имеют смысл Я же говорю вы все — сугубые теортетики. Не найденные нас не интересуют, от слова «вообще».

То есть вас интересуют только те баги которые вы нашли, и совсем не интересуют те которые ещё остались? Жесть какая-то

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


Что ты понимаешь под бизнес логикой? Баг с единицами измерения в Mars Climate Orbiter — это бизнес логика?
Прямое списание AUD со счёта USD — это бизнес логика?

EP>>И что? На динамическом языке можно написать корректную и надёжную программу, и наоборот — на статическом некорректную и ненадёжную

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

Что ты вкладываешь в понятие "мега помогает"?

M>Любые наводящие вопросы растворяются в словоблудии и наборе все более абсурдных условий, в которых она (якобы) помогает.


Переход на хамство в ответ на терпеливые объяснения — бывает и такое на RSDN
Re[75]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.03.15 04:31
Оценка: 32 (1)
Здравствуйте, jazzer, Вы писали:

J>Ты издеваешься, что ли? Я ведь уже отвечал на этот вопрос. Считай, что ордер в моей статье пришел из базы. Или тебе SQL нужен?

Меня просто не устраивает ваш ответ

S>>б) нет функции обработки, которая бросает runtime ошибку для "статически-верифицируемых" свойств.


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


Ключевое выделено. Ещё раз объясню простую вещь, которая до вас никак не хочет дойти: вы написали в два с половиной раза больше кода, при этом не совершив никакой полезной работы.
Количество рантайм проверок — такое же; устойчивость кода к ошибкам программиста — такая же.
Ну так если нету разницы, то зачем платить больше?

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

Это не говоря о том, что ограничить места, из которых можно позвать определённые функции, можно гораздо более простым способом — например, сделав их приватными и перечислив исключения во friend-декларации
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[71]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.03.15 04:44
Оценка: +1
Здравствуйте, jazzer, Вы писали:

J>Он не эквивалентен в смысле возможности написать ошибочный код.

Ну конечно же эквивалентен.

J>У тебя увеличить amount по ошибке можно в обоих етках и вообще за пределами ифа. У меня нет. Именно в этом разница.

Можно. И у вас — тоже можно, только на уровень выше.
Вы заменяете код вида var a = 5/b на код вида if (b==0) throw new DivisionByZeroException() else a =5/b;.

J>Блин, ну ты же сам писал: "Код, содержащий незаконный переход, просто не скомпилируется."

J>Вот что в твоем коде может быть:
S>>
S>>increase_amount(Order& o, Money amt)
S>>{
J>    o.Amount += amt; // незаконно! но компилируется!
S>>  if(o.HasRisk)
S>>  {  // doing nothing 
J>      o.Amount += amt; // незаконно! но компилируется!
S>>  }
S>>  else
S>>  {
S>>    o.Amount += amt;
S>>  }
J>    o.Amount += amt; // незаконно! но компилируется!
S>>}
S>>

J>А в моем всего этого быть не может в принципе.
Омг. Ну и что?

J>Потому что, как ты правильно выразился, у меня код двухслойный: есть слой функций, выполняющих реальные действия (типа increase_amount), есть слой функций бизнес-логики (типа try_to_change_amount), которые зовут функции реального слоя. Так вот код функций слоя бизнес-логики в моем случае может быть написан только по определенным правилам, задаваемым свойствами, отображаемыми в типы. Его нельзя написать произвольно, просто от балды накидав вызовов функций реального слоя.

Вы неправильно понимаете результат собственных действий.
Вот у вас есть слой "небезопасных" функций — тех, которые нельзя вызывать с произвольными агументами. Допустим, например, что можно нечаянно получить ордер с отрицательной суммой.
Чтобы защитить эти "голые" функции, вы оборачиваете их в функции, которые выполняют рантайм-проверку аргументов перед вызовом. А "голые" функции вы прячете путём описания требований к аргументам в сигнатуре.
Победа?
Нет. Я точно так же могу ошибочно вызвать функцию-оболочку откуда угодно, и компилятор прекрасно пропустит эту заведомую ошибку.
Считайте, что коду "бизнес-логики" видны только нетипизированные функции-оболочки. Он внезапно окажется точно таким же, как и в исходном нетипизированном варианте.
Только внутри написано чуть больше кода для предотвращения "ошибок", которых в исходном коде не было вовсе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[72]: Haskell нужен! (в Standard Chartered Bank)
От: Sinclair Россия https://github.com/evilguest/
Дата: 05.03.15 05:08
Оценка: 36 (1)
Здравствуйте, jazzer, Вы писали:
S>>Вот именно. Т.е. мы так никуда и не ушли от рантайм-проверок.
J>Я где-то говорил, что мы от них ушли?
Вроде нет, но без этого ухода теряется весь смысл статической верификации.
J>Не понял.
Сейчас разберёмся.
J>на первый взгляд — шило на мыло (хотя уже видна разница),
Да, совершенно верно.

J>но стоит написать функцию f посложнее — и разница сразу вылезет наружу: у меня все проверится один раз и дальше будет работа с типизированными объектами (и типизацию сможет проверить компилятор, и в типизированном коде уже не будет никаких исключений), а у тебя все будет проверяться каждый раз (тупо лишняя работа) и исключения будут вылетать из глубины операторов, а не из функции бизнес-логики f.

Воот. Теперь мы наконец говорим на нужную тему.

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

Отлично. С арифметикой мы разобрались — именно по описанным вами причинам в большинстве современных промышленных ЯП арифметика типизирована.

Проблема возникает именно при попытке перенести тот же подход на бизнес-логику типа обработки заказов.
Как мы уже обсуждали (правда, не все смогли не проигнорировать эту часть обсуждения), код обработки заказов мало похож на код по решению уравнений Шредингера.
В нём как правило не получается написать даже a = b*c, а уж "написать функцию f посложнее" и вовсе невозможно.
Потому что там не будет непрерывных цепочек a=b*c+d-(e-f)/g. А будут ровно цепочки типа "поднять из базы — двинуть на шаг вперёд".
Из-за этого не получается ничего сэкономить на типах — нету повторного использования. Increase Amount уже вызывается ровно из одного места, и проверить корректность этого места вручную проще, чем навесить какие-то монструозности на её агументы, чтобы эти монструозности "проверили" на корректность три-четыре строки.


Вы всё время пишете код, подразумевая "ну, на самом-то деле всё совсем не так, и вот тогда-то типизация ого-го!".
А я читаю код как попытку привести реальный пример. И рассматриваю именно этот код, а не "ну, далее вы сами должны догадаться, что я прав".
Представьте, что я вам пытаюсь объяснить, что такое "рифма". И говорю: "ну, вот например: белеет парус одинокий, в тумане моря голубом. Можно продолжать и дальше, но, я думаю, вы и сами поняли, что к чему".

Те мои посты, обращённые к Мамуту, которые вам "понравились", вы, похоже, прочитали по диагонали. Ну или просто решили проигнорировать фразы типа "на воображаемом языке" и "гипотетически возможно". Поэтому я вам ещё раз объясню: чтобы ваши теоретические экзерсисы смогли принести практическую пользу, нужно не только научиться отслеживать типы в пределах развесистой функции f, но и решать проблему функции f, порезанной на сотню маленьких фрагментов. Нужно научиться отслеживать тип ордера за пределы функций Save и Load.

J>Ты точно со мной разговариваешь?

Ну да.

J>ЗЫ А почему вдруг на вы, если не секрет?

А я практически со всеми тут на вы.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[82]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 05.03.15 10:40
Оценка:
M>>Может. Возможно. Может. Возможно. Это мы уже проходили
Автор: Mamut
Дата: 26.02.15
:


EP>Тебя удивляет наличие условий для целесообразного применения какой-то техники?


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

EP>>>Например предотвратит передачу MoneyAUD в MoneyUSD, или например радикально сократит количество перестановок аргументов валидных с точки зрения типов

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

EP>Есть:

EP>есть только 6 перестановок аргументов которые скомпилируются.

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

EP>>>Но какие из преимуществ динамического языка тогда останутся?

M>>Вопрос должен быть поставлен наоборот: какие из преимуществ стат. языка останутся?

EP>Почему наоборот-то? Ты предлагаешь в динамическом языке делать все runtime проверки, которые в статическом языке делаются в compile-time. При этом у тебя даже нет гарантии что эти runtime проверки поймают баг во время unit-test'ов.


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

Почему я должен верить вам наслово, что эти самые проверки принесут вот мне лично в нашей далеко не маленькой системе какой-то ощутимый бенефит?

(Если что, я прекрасно понимаю бенефиты, которые типы приносят в рефакторинг, например).

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


Ты себе придумал какой-то тезис, и им размахиваешь. Молодец.

Скорость разработки у меня та же, или выше. Усилия я потратил ровно те же. Хотя вру. Усилия я потратил намного меньше. Потому что в то время, пока вы не осилили покрыть типами четыре условия, я на динамическом языке успел написать реальную
Автор: Mamut
Дата: 06.02.15
задачу банальными ифами и покрыть это тестами. А вы скоро месяц уже не можете решить в десть раз более просту задачу

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

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

EP>>>Найденным?

M>>А только они имеют смысл Я же говорю вы все — сугубые теортетики. Не найденные нас не интересуют, от слова «вообще».
EP>То есть вас интересуют только те баги которые вы нашли, и совсем не интересуют те которые ещё остались? Жесть какая-то

Нас интересуют все баги. Но в то время, как ты теоретизируешь о том, как у нас со счета USD списывается AUD, у нас такого на практике не происходит.

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

При этом тикетов у нас в системе скоро будет несколько десятков тысяч. Собственно багов из них — меньше десяти процентов (остальное — требования к изменению функционала). Из этих багов связанные с проблемами в типах? 1-2 в год

Какой именно бенефит нам принесет, например, инвестиция в покрытии всего этого кода информацией о типах? Какой именно бенефит нам принесет стат. типизация на наших реальных задачах, если вы тут все хором показали, что вы не можете внятно решить даже 1% от 1% от 1% от решаемых в коде задач?

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

M>>Любые наводящие вопросы растворяются в словоблудии и наборе все более абсурдных условий, в которых она (якобы) помогает.

EP>Переход на хамство в ответ на терпеливые объяснения — бывает и такое на RSDN

Извини, у меня иммунитет на сказки и презрение к сказочникам. Ваши «терпеливые объяснения» в 99% случаев — именно сказки, демагогия и словоблудие


dmitriid.comGitHubLinkedIn
Re[76]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 05.03.15 12:58
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>То есть мы отлавливаем ошибку отсутствия if(hasRisk) выше по стеку?

S>Да, изобразить это без буста не удастся. Впрочем, полезность этой процедуры не больше нуля. Забыть сделать проверку выше по стеку ничуть не более вероятно, чем забыть сделать проверку прямо в этой функции. Поэтому в результате мы имеем программу, в которой написаны две проверки на наличие риска — одна статическая на шаблонах, а другая — рантайм.
S>Ну, либо программист забыл добавить первую из них, и компилятор ничем ему не помог.

Забыть проверку PROP_IF выше по стеку нельзя, будет ошибка компиляции.
Re[71]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 05.03.15 12:58
Оценка: +1
Здравствуйте, Sinclair, Вы писали:

S>Я вам напомню, что функция, в которую не было предусмотрено передачи невалидного ордера, у нас уже была. Это increase_amount.

S>Сигнатуру try_to_change_amount пришлось "испортить" из-за того, что есть функция LoadOrder, которая умеет загружать только "неизвестно какие" ордера.

Все промежуточные функции будут требовать валидный ордер (неявным образом, просто из-за того, что где-то в глубине сидит increase_amount), кроме одной, где-то наверху, которая PROP_IF и делает.
try_increase_amount — упрощенный пример. Между PROP_IF и функцией, в которой закодировано требование к HasRisk (increase_amount), может находиться еще куча функций.
Re[73]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 05.03.15 13:03
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


Ну, примерно так.

S>Т.е. в случае незатейливой increase_amount в ней все требования проверяются динамически, и в случае их нарушения пользователь получает Message Box с объяснением причин.

S>А вы предлагаете обязать программиста, использующего increase_amount, провести проверки до вызова, чтобы в случае провала проверок пользователь получил MessageBox с объяснением причин.

Да.

S>Единственная проблема, которую ваше "решение" решает — это обеспечение разных текстов ошибок в разных контекстах (ну или, скажем, чтобы вызовы через web получали 400 bad request, а вызовы из rich application показывали MessageBox). Но для этой проблемы есть старое и гораздо более удобное решение — выброс исключений. Обязанность коммуницировать с пользователем делегируется вверх по стеку; а сам набор проверок гарантированно выполняется благодаря инкапсуляции.

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

Как раз избыточные проверки во всех промежуточных слоях и устраняются. Остается один PROP_IF (один PROP_IF на одно свойство, если быть точным) где-то на входе, скорее всего сразу после загрузки ордера, и где-то в глубине системы вызов increase_amount. Весь код между ними свободен от проверок, и в то же время компилятор гарантирует, что increase_amount вызывается в корректном контексте.
Re[72]: Haskell нужен! (в Standard Chartered Bank)
От: AlexRK  
Дата: 05.03.15 13:12
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


Да нет никаких "функций-оболочек". В смысле каких-то тонких оболочек над "беззащитными" функциями. Эта "оболочка" покрывает толстый слой кода, а может и всю систему вообще. Внутри этой оболочки производится куча действий. Некоторые из которых "беззащитные", но компилятор гарантирует, что они заведомо находятся в "оболочке" (хотя она может находиться на 100 уровней выше).
Re[72]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 05.03.15 13:49
Оценка:
S>Вот у вас есть слой "небезопасных" функций — тех, которые нельзя вызывать с произвольными агументами. Допустим, например, что можно нечаянно получить ордер с отрицательной суммой.

Реальный код из нашей системы:

  if
    Amount < -49 ->  % allow -49 ore
      exit({negative_order, send_aborted, OrderNo});


Никаких «нечаянно» Все предусмотрено


dmitriid.comGitHubLinkedIn
Re[72]: Haskell нужен! (в Standard Chartered Bank)
От: Mamut Швеция http://dmitriid.com
Дата: 05.03.15 13:51
Оценка:
ARK>Все промежуточные функции будут требовать валидный ордер (неявным образом, просто из-за того, что где-то в глубине сидит increase_amount), кроме одной, где-то наверху, которая PROP_IF и делает.
ARK>try_increase_amount — упрощенный пример. Между PROP_IF и функцией, в которой закодировано требование к HasRisk (increase_amount), может находиться еще куча функций.

Можно увидеть это в виде полной реализации моего примера? + что Синклер сказал
Автор: Sinclair
Дата: 05.03.15


dmitriid.comGitHubLinkedIn
Re[76]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 05.03.15 15:54
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


J>>Ты издеваешься, что ли? Я ведь уже отвечал на этот вопрос. Считай, что ордер в моей статье пришел из базы. Или тебе SQL нужен?

S>Меня просто не устраивает ваш ответ
Чем конкретно? Надо все-таки SQL писать?

S>>>б) нет функции обработки, которая бросает runtime ошибку для "статически-верифицируемых" свойств.


S>Ключевое выделено. Ещё раз объясню простую вещь, которая до вас никак не хочет дойти: вы написали в два с половиной раза больше кода, при этом не совершив никакой полезной работы.

S>Количество рантайм проверок — такое же
да

S>устойчивость кода к ошибкам программиста — такая же.

Ну конечно же нет
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[72]: Haskell нужен! (в Standard Chartered Bank)
От: jazzer Россия Skype: enerjazzer
Дата: 05.03.15 16:18
Оценка:
Здравствуйте, Sinclair, Вы писали:

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


J>>Он не эквивалентен в смысле возможности написать ошибочный код.

S>Ну конечно же эквивалентен.
Ну конечно же нет.

J>>У тебя увеличить amount по ошибке можно в обоих етках и вообще за пределами ифа. У меня нет. Именно в этом разница.

S>Можно. И у вас — тоже можно, только на уровень выше.
Ну конечно же нет.

J>>Блин, ну ты же сам писал: "Код, содержащий незаконный переход, просто не скомпилируется."

J>>Вот что в твоем коде может быть:
J>>А в моем всего этого быть не может в принципе.
S>Омг. Ну и что?

Отличный ответ "Срезал!" (с)
О чем дальше тут говорить — хз.

S>Вот у вас есть слой "небезопасных" функций — тех, которые нельзя вызывать с произвольными агументами. Допустим, например, что можно нечаянно получить ордер с отрицательной суммой.


S>Чтобы защитить эти "голые" функции, вы оборачиваете их в функции, которые выполняют рантайм-проверку аргументов перед вызовом. А "голые" функции вы прячете путём описания требований к аргументам в сигнатуре.


Вот здесь у тебя ошибка в понимании моего кода, имхо. И тут моя вина тоже есть.
Ты трактуешь increase_amount и try_to_change_amount в моем примере как пару. Типа каждый раз, когда ты хочешь позвать одно, ты должен позвать другое, и это другое — обертка для первого. И поэтому вдвое больше кода и прочая и тлен.

Так вот это не так. Функции так называются просто потому, что я реализовывал задачу Мамута, в которой была ровно одна операция — увеличение ордера (и то, я назвал функцию не try_to_increase_amount, а try_to_change_amount).
На самом деле никакой связки эти две функции в реальном коде образовывать не будут. Не будет никакого try_to_change_amount, а будет какой-нть process_order (я, кстати, вначале так и написал, но потом переименовал; как выясняется, зря).
И в process_order будет разветвленная логика (по выполнению одного шага, если тебе так угодно, но мы же не знаем, загрузив ордер из БД, какой именно шаг можно исполнить сейчас), с обработкой рантайм-ошибок, кривых данных и прочего.
Этих process_order может быть дофига, вообще говоря — по нажатию одной из кнопок в гуе, по приходу одного из многих сообщений по сети и т.д. и т.п. Будет process_button_a, process_button_b, process_network_message_c.
В каждом будет какая-то логика.
Так вот все эти многоэтажные типы задают правила, по которым может быть написан код всех вот этих process_xxx, чтобы гарантировать, что незаконных переходов в них не будт.

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

Могу привлечь аналогию с ООП. Если у тебя настолько примитивная (архитектурно) программа, что деление на классы ничего полезного в ней не даст, то, наверное, ООП в ней не нужен — это будет ровно один класс на всю программу, что смотрится маразматично (ну примерно как смотрится Java-программа с классом HelloWorldApp с единственной функцией main). Но стоит программе немножко усложниться — и вдруг ООП становится прекрасным работающим средством.

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

You will always get what you always got
  If you always do  what you always did
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.