LINUX.ORG.RU

Анализ пользователей Common Lisp и Racket

 , ,


11

7

Common Lisp разрабатывался и используется в предположении, что пользователь программы — программист. Поэтому из языка намеренно исключены сложные для понимания конструкции (пользователь не обязательно квалифицированный программист), поэтому в языке мощнейший отладчик, позволяющий без остановки программы переопределять функции и вообще делать что угодно. Но из-за этого документация по большей части библиотек Common Lisp существует только в виде docstring и комментариев в коде (некоторые вообще считают, что код сам себе документация). Из-за этого обработка ошибок почти всегда оставляется на отладчик (главное сделать рестарт «перезапустить с последней итерации», а там пользователь сам разберётся). Из-за этого в программе проверяется только happy path (пользователь ведь «тоже программист»).

Racket разрабатывался и используется в предположении, что пользователь программы не программист, а задача разработчика написать программу так, чтобы она корректно работала при любых входных данных (если данные некорректны, то сообщала об этом в том месте, где данные были введены). Поэтому в языке эффективная библиотека для написания тестов, система контрактов на уровне модулей, макимально широкий спектр инструментов программирования (разработчик должен быть профессионалом!). Также реализована идея инкапсуляции: считается, что пользователь модуля не должен знать особенности реализации и, более того, не может в своём коде изменить функцию чужого модуля если это явно не разрешено разработчиком того модуля. Исходный код разумеется доступен, но его не требуется смотреть, чтобы использовать модуль. Достаточно документации. Поэтому реализована мощнейшая система документировния Scribble, а при реализации макроса есть возможность обеспечить указание на ошибки в коде, предоставленном макросу пользователем, не показывая потроха макроса.

И поэтому в Racket нет CLOS (есть как минимум две реализации, но не используются) - провоцирует заплаточное программирование (monkey patching), поэтому отладчик намеренно ограничен (если ты отлаживаешь программу, значит ты не знаешь как она должна работать!), поэтому нет разработки в образе (image based) - она провоцирует разработку через отладку (а значит непонимание программы и проверку только happy path).

Таким образом, Racket и Common Lisp несмотря на внешнее сходство являются очень разными языками. И я рекомендую писать на Racket, если только конечными пользователями программы не являются исключительно программисты на Common Lisp.

Взято с http://racket-lang.blog.ru/#post214726099

Хотелось бы знать, что по этому поводу думают пользователи ЛОРа. А также, мне кажется, что для Java и C++ будет где-то такая же разница.

★★★★★

Ответ на: комментарий от den73

4. Если у меня не будет разработки в образе, то и лисп тогда не нужен. Есть Java и C#.

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

2. Будет ли в программе только проверка «happy path» - это зависит только от программиста.

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

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

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

3. Инкапсуляция в CL возможна, на уровне пакетов.

Ну конечно.

И далее грепать :: по всем сорсам, чтобы найти нарушения.

Это должен язык делать, а не программист.

anonymous
()
Ответ на: комментарий от iVS

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

Ну а в динамике найдутся при первом запуске. Разница в чем? Что типы дали?

Если речь о разработке сверху вниз, то в хаскеле можно так. Я не вижу никаких проблем с типами. Всегда все равно мы держим в голове типы входящих и исходящих данных. И если я переложу часть забот из головы на компилятор — будет только проще.

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

anonymous
()
Ответ на: комментарий от anonymous

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

Можно зевнуть и использовать левую функцию с такой же сигнатурой, и компилятор это скомпилирует.

Или щас начнешь заливать про супер-дупер TTD и 100% покрытие?

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

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

mv ★★★★★
()
Ответ на: комментарий от mv

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

Статикофилы как раз и не понимают того факта, что написанный в динамике с нормальным реплом код кучу раз запускается к тому моменту (даже без тестов вообще), как написан. И во время этих запусков бяки отлавливаются. У них навязчивая идея, что программу запускать вообще нельзя. Ее надо только тайпчекать. А потом выкидывать. Потмоу что запущенная программа - это ад и погибелъ их статической души.

anonymous
()
Ответ на: комментарий от anonymous

Ну а в динамике найдутся при первом запуске.

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

Например, выводить типы в уме приходится.

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

iVS ★★★★★
()
Ответ на: комментарий от iVS

В динамике ошибка в ветке не находится, пока по ней не пойдешь.

А в статике ошибка типов не находится, если она типами не фиксирована.

Чего? Не знаешь, что передается в ф-цию, а что выводится?

Ну этого даже компилятор в общем случае не знает (по-этому узнать тип «одной командой» не выйдет). А даже когда компилятор знает - этот тип не пишут (вывод типов ведь) и из кода его узнать нельзя. То есть в 90% случаев программист на хаскеле не знает что передается в функцию, а что выводится, да. И то что ему приходится на каждый чих спрашивать у компилятора (без гарантий ответа при этом) - это какбы очень сильный минус, а совсем не плюс.

anonymous
()
Ответ на: комментарий от iVS

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

А в статике ты будешь писать без тестов? И типы переписывать не будешь, когда абстракция поменяется, лол?

anonymous
()
Ответ на: комментарий от anonymous

А в статике ошибка типов не находится, если она типами не фиксирована.

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

Ну этого даже компилятор в общем случае не знает (по-этому узнать тип «одной командой» не выйдет). А даже когда компилятор знает - этот тип не пишут (вывод типов ведь) и из кода его узнать нельзя. То есть в 90% случаев программист на хаскеле не знает что передается в функцию, а что выводится, да. И то что ему приходится на каждый чих спрашивать у компилятора (без гарантий ответа при этом) - это какбы очень сильный минус, а совсем не плюс.

В твоей параллельной Вселенной другой хаскель! Если таких случаев 90%, покажи пример, когда я не знаю тип ф-ции?

iVS ★★★★★
()
Ответ на: комментарий от iVS

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

Дело не в возможностях компилятора. Зависимые типы могут ВСЕ ошибки отловить, но если ты не укажешь в типе ф-и сортировки что она должна сортировать - то компилятор просто не знает, что ему отлавливать.

В твоей параллельной Вселенной другой хаскель! Если таких случаев 90%, покажи пример, когда я не знаю тип ф-ции?

x >>= f - скажи пожалуйста, в какой монаде выполняется этот бинд?

anonymous
()
Ответ на: комментарий от anonymous

x >>= f - скажи пожалуйста, в какой монаде выполняется этот бинд?

Так в хаскеле не делается, без декларации типов. Если у тебя так в 90% — это очень плохой признак.

iVS ★★★★★
()
Ответ на: комментарий от tailgunner

Речь о динамической и статической типизации, а не «динамизме» в твоем понимании.

Да, строгую и статическую я перепутал. Я имел в виду статическую типизацию, я под ней я понимаю наличие декларированных типов у переменных и функций (Хаскель не учил, возможно в нём это не так, но меня это не интересует :). Грань между динамической и статической типизацией, вообще-то не так просто провести, поскольку типы образуют иерархию. В частности, в лиспе все переменные и функции статически имеют тип t, а в каком-нибудь C++ указание типа переменной MyClass x лишь сужает возможный набор типов для x, но не определяет тип однозначно, поскольку у MyClass есть потомки.

Запуск тестов является запуском программы?

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

den73 ★★★★★
()
Ответ на: комментарий от den73

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

Да ладно. Очень даже просто: в динамике типы определяются в рантайме. А ты сейчас софистикой занимаешься. Так и я могу сказать, что Tcl статически типизирован типом «строка». И т.п.

anonymous
()
Ответ на: комментарий от den73

Запуск тестов является запуском программы?

Это всё же отчасти вопрос терминологии, не находишь?

Отчасти.

Одно дело - запустить юнит-тесты, а другое - какую-нибудь систему с гуем, где надо ещё кликнуть на пункт меню и нажать кнопку.

Не все такие ошибки отлавливаются юнит-тестами.

tailgunner ★★★★★
()
Ответ на: комментарий от iVS

Так в хаскеле не делается, без декларации типов.

Правда что ли? А как делается?

Если у тебя так в 90% — это очень плохой признак.

Это не у меня, это у хаскелистов, упоротых по «надо же делать универсально» в 90% так. И, да - это ОЧЕНЬ плохой признак.

anonymous
()
Ответ на: комментарий от den73

Ну если ты считаешь нормальным грепать сорцы для поиска ошибок - то ок, чо.

anonymous
()
Ответ на: комментарий от iVS

Учи матчасть

То есть ответить ты не в состоянии? А ничего что в сорцах хаскельных проектов чуть менее чем всегда именно x >>= f? Или среди хаскеллистов никто не знает матчасти?

anonymous
()

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

anonymous
()
Ответ на: комментарий от anonymous

То есть ответить ты не в состоянии?

Ты же не просто спросил. Сначала тут спорил и доказывал про хаскель, а потом на чистом глазу заявляет, что о предмете спора ничего не знает, лол)))

iVS ★★★★★
()
Ответ на: комментарий от anonymous

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

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

Как обычно фаны динамики форсят TDD (а что им остается?).

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

anonymous
()
Ответ на: комментарий от iVS

Ты же не просто спросил. Сначала тут спорил и доказывал про хаскель, а потом на чистом глазу заявляет, что о предмете спора ничего не знает, лол)))

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

anonymous
()
Ответ на: комментарий от anonymous

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

Расскажи, как ты пришел к такому выводу? Опросил всех людей, пишущих на хаскеле?

iVS ★★★★★
()
Ответ на: комментарий от iVS

Расскажи, как ты пришел к такому выводу?

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

anonymous
()
Ответ на: комментарий от anonymous

Я видел опенсорсный код на хаскеле

И как ты по нему сделал вывод о всех людях, пишущих на хаскеле?

iVS ★★★★★
()
Ответ на: комментарий от iVS

И как ты по нему сделал вывод о всех людях, пишущих на хаскеле?

Не обо всех, а о большей части.

anonymous
()
Ответ на: комментарий от Hjorn

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

дома на своём локалхосте я тебе разрешаю делать что угодно. Хоть программу из одной строчки на перле.

Желательно, что-бы никто этого не видел.

emulek
()
Ответ на: комментарий от anonymous

Статика требует дополнительных ресурсов на разработку

4.2

Статика ускоряет разработку. Говнокод, в котором ты кастуешь строку в число у тебя тупо не соберётся, а в динамике «всё будет хорошо». Часто даже правильно будет в тестах работать, например если «пусто» у тебя кастуется в 0. Поначалу. А когда вместо «пусто» у тебя скастуется «true» в ноль, будет несмешно. Я помнится долго искал ошибку в своём говнокоде на php, в котором были смешаны числа и строки в одном выражении. Для некоторых данных получалось то, что надо, но иногда получалась фигня. Проблема в том, что тестирование эту фигню не покрывало, и вылезла она через полгода, после написания. Искал я эту хрень неделю.

С тех пор, в говнопхп я не ленюсь всё явно типизировать, там ВНЕЗАПНО есть и intval(), и operator===, и всякие strcmp(). Но вот смысл в динамике, если я её всё равно НЕ использую, т.к. она гнлючит? Или тестов нужно Over9000? А когда я код писать буду?

И не важно где ты пишешь - в динамике или в статике

в статике меньше степеней свободы. Ошибиться сложнее.

emulek
()
Ответ на: комментарий от tailgunner

Казалось бы, причем тут ОО...

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

хамло

О чем ты, болезный? ОО - помойка мутабельных состояний и размазанной логикой. Все большие проекты, а часто и маленькие, благодаря ОО также превращаются в помойку. У тебя есть знания и опыт только в оо программировании. Т.о. твой оригинальный мессадж является очередным голосом из оо помоки. Никакого хамства. Лишь голая констатация факта.

Ritmik
()
Ответ на: комментарий от tailgunner

Не смог пройти мимо. Показатель уровня tailgunner-а, после которого все встает на свои места.

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

Выявление ошибок несовпадения типов без запуска программы.

Перефразирую. анонимус спросил tailgunner-а привести пример задачи, для решения которой использование подхода с фичей А тот считает лучше, чем использование подхода с фичей Б, и анонимус пообещал показать как она решается при помощи подхода с фичей Б. На что tailgunner отвечает: задача - иметь фичу А. Что явно показывает уровень логики tailgunner-а и прочих адептов типизированных яп.

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

Ritmik
()
Ответ на: комментарий от Ritmik

каждый раз из оо помойки

Казалось бы, причем тут ОО...

Ты даже не понимаешь разницу между динамически типизиоованным оо и динамически типизированных не оо языком

Болезный, ты бредишь. Об ОО я вообще не говорил.

tailgunner ★★★★★
()
Последнее исправление: tailgunner (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Об ОО я вообще не говорил.

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

Ritmik
()
Ответ на: комментарий от Ritmik

Болезный, ты бредишь. Об ОО я вообще не говорил.

Хосспаде, никто не утверждает, что это ты говорил, внимательный ты наш

Тогда откуда ты взял, что я не понимаю разницы между каким-то там ОО и чем-то еще? Нет, не отвечай. Прими таблеточку и баиньки.

tailgunner ★★★★★
()
Ответ на: комментарий от emulek

Статика ускоряет разработку.

Конечно нет. Если в динамике просто пишешь и - just works, то в статике надо еще повоевать с компилятором.

Говнокод, в котором ты кастуешь строку в число у тебя тупо не соберётся, а в динамике «всё будет хорошо».

Ни разу не кастовал строку в число.

Часто даже правильно будет в тестах работать, например если «пусто» у тебя кастуется в 0. Поначалу. А когда вместо «пусто» у тебя скастуется «true» в ноль, будет несмешно.

Зачем ты рассуждаешь о том, чего не бывает?

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

Это проблема слабой типизации. Слабая типизация - говно офк, и что пехепе что сишка - тут на равных. Мы же говорим о strong dynamic vs strong static - тут описанных тобой проблем не бывает.

Но вот смысл в динамике, если я её всё равно НЕ использую

Конечно, используешь. Тебе не приходится тратить время на исправление ошибок чекера и проставление типов - это уже использование, которое существенно ускоряет процесс разработки.

в статике меньше степеней свободы. Ошибиться сложнее.

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

anonymous
()
Ответ на: комментарий от tailgunner

Тогда откуда ты взял, что я не понимаю разницы между каким-то там ОО и чем-то еще?

Потому что для тебя это «что-то ещё»? И ты не знаешь что, правда?

Прими таблеточку и баиньки.

Это все, что ты можешь ответить? Очень показательно для помоечного критика.

Ritmik
()
Ответ на: комментарий от Ritmik

Очень показательно для помоечного критика.

критика

/me .oO( у поциента проявляется новый симптом - он считает себя пейсателем. Продолжаем наблюдение. )

tailgunner ★★★★★
()
Ответ на: комментарий от emulek

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

В статике ещё хуже. Есть переменная «доля чего-то в процентах». Тип должен быть 0..100. Но у нас в языке нет 0..100, а есть в лучшем случае byte, а в худшем «положительное целое число». Более того Проверка типа percent f(percent a, percent b) { return a + b; } как правило проходит. В то время как очевидно, что для a = b = 60 уже нарушение контракта.

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

monk ★★★★★
() автор топика
Ответ на: комментарий от tailgunner

критика

считает себя пейсателем

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

Ritmik
()
Ответ на: комментарий от monk

Наконец-то пошли хоть какие-то аргументы. А то вся трепотня анонимуса выше сводится к тому, что «в лом писать декларации».

anonymous
()
Ответ на: комментарий от monk

Есть переменная «доля чего-то в процентах». Тип должен быть 0..100. Но у нас в языке нет 0..100, а есть в лучшем случае byte, а в худшем «положительное целое число»

А что мешает создать (в Си++, к примеру) класс «проценты»?

очевидно, что для a = b = 60 уже нарушение контракта.

Да. И так же очевидно, что:

percents p;
miles m;

return m+p

тоже нарушение контракта. Отслеживаемое компилятором.

Типы часто дают ложное ощущение «скомпилировалось, один тест прошёл, значит всё верно»

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

tailgunner ★★★★★
()
Ответ на: комментарий от Ritmik

ОО - помойка мутабельных состояний и размазанной логикой

Вах-вах! Суровый функцианальный воен ITT. Все в машину!

anonymous
()
Ответ на: комментарий от mv

Можно зевнуть и использовать левую функцию с такой же сигнатурой, и компилятор это скомпилирует.

Это нужно как-то очень широко зевать. В динамике же можно написать любую херню и молиться, чтобы тесты её покрыли. Особенно доставляет чужой говнокод без тестов и документации, где только дебагер и поллитровка могут помочь разобраться, что же имел ввиду аффтар. Зато сэкономили время на декларациях, ЛОЛ!

anonymous
()
Ответ на: комментарий от monk

для a = b = 60 уже нарушение контракта.

120% - вполне корректный результат.

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

anonymous
()
Ответ на: комментарий от tailgunner

тоже нарушение контракта. Отслеживаемое компилятором

Смотря как определить. Если typedef int miles; typedef int percents; то не отследит. А если как положено, то даже чтобы сложить проценты с процентами изрядно гемороя будет. Или покажи кусок кода, как ты определяешь miles и percents.

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

120% - вполне корректный результат.

Если здесь хранится процент анонимусов среди пользователей ЛОРа, то нифига не корректный. Я же говорю, что «предположим тип предметной области — доля чего-то. Тогда должно быть 0..100, но язык такое не позволяет»

monk ★★★★★
() автор топика
Ответ на: комментарий от anonymous

Это нужно как-то очень широко зевать.

посмотри сколько функций с одинаковой сигнатурой: http://www.haskell.org/hoogle/?hoogle=Int->Int.

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

monk ★★★★★
() автор топика
Ответ на: комментарий от monk
typedef LimitedInteger<int, 0, 100> percents;
typedef UnlimitedInteger<unsigned int> miles;

Геморрой и реверансы перед компилятором — в библиотеку утилит.

ilammy ★★★
()
Ответ на: комментарий от monk

Смотря как определить. Если typedef int miles; typedef int percents; то не отследит

Зачем ты приводишь в качестве примеров заведомо неработоспособные подходы?

А если как положено, то даже чтобы сложить проценты с процентами изрядно гемороя будет. Или покажи кусок кода, как ты определяешь miles и percents.

Я никак не определяю, потому что пишу на Си и Python; но к твоим услугам куча библиотек на Си++, начать можно с Boost.Units.

tailgunner ★★★★★
()
Ответ на: комментарий от anonymous

А то вся трепотня анонимуса выше сводится к тому, что «в лом писать декларации».

А есть хоть какаято причина писать декларации, если можно не писать?

anonymous
()
Ответ на: комментарий от anonymous

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

Зачем покрывать всякую херню тестами? Не надо.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.