Комментарии 224
Как принято сейчас говорить, выдал базу.
Можно было поступить проще. Первой строкой дать ссылку на https://ru.wikipedia.org/wiki/Языково-ориентированное_программирование
а второй - поставить точку. :)
При чем тут DSL вообще? Я говорил о языках общего назначения.
Чтобы было проще, представьте, что "языки общего назначения" - это DSL-и с предметной областью "общее назначение".
Затем, попробуйте формально описать что это за область "общее назначение" такая, и убедитесь, что такой области не существует. Затем, если почитать историю возникновения каждого языка, окажется, что все не самопальные языки (Си, лисп, фортран, sql, ...), как ни странно, были доменными. (Не говоря уже о самопалках вроде перлов либо питушманов.)
К примеру, домен Си - вычислители образца https://ru.wikipedia.org/wiki/Архитектура_фон_Неймана , отсюда на Си не удобно, реализовывать к примеру, вычисления геометрии либо теории поля, хотя, конечно, возможно.
Ну такое себе. Если вам не нужно, это нк означает, что и другим не надо.
Производительность - а почему вы меряете производительность только скоростью исполнения?
Мне, например, от производительности важно - потребление памяти, сколько при этом cpu будет задействовано, нагрузку на gc (если мы говорим о языке с ним).
Тоже самое и с остальными пунктами. Слишком однобоко.
И да. Языки сами по себе не используют. Их используют в связке с туллингом вокруг них. И так повелось, что чтобы тулинг сделать удобнее нужно и сам язык изменить немного. Это нормально.
это не означает, что и другим не надо
А эти другие, они сами могут внятно ответить за вопрос: «зачем им это надо»?
Мне, например, от производительности важно […]
Я это всё тоже имел в виду. Скорость исполнения — просто довлеющий критерий, все остальные от него так или иначе зависят.
чтобы тулинг сделать удобнее нужно и сам язык изменить немного
Если язык спроектирован не пьяным бараном — нет. Адекватные люди пишут инструментарий вместе с языком, а не столетие спустя.
А эти другие, они сами могут внятно ответить за вопрос: «зачем им это надо»?
Да, вполне. В мире вообще достаточно много адекватных людей могущих обосновывать и принимать решения самостоятельно.
Скорость исполнения — просто довлеющий критерий, все остальные от него так или иначе зависят.
Сейчас скорость у большинства стримовых языков более менее одинакова или не принципиально отличается (относительно решаемых задач), но вот потребление памяти и процессорного времени может отличаться в десятки раз. Поэтому я бы тут не был так котигоричен.
Если язык спроектирован не пьяным бараном — нет. Адекватные люди пишут инструментарий вместе с языком, а не столетие спустя.
Ну такое. Приведите примеры языков которые не пьяные бараны проектировали на ваш взгляд.
Я в тексте уже привел такой пример. Еще Elixir, LISPы, Idris, Haskell (создатели хотя бы понимали, что они разбредаются кто в лес, кто по дрова, отсюда и девиз), Julia, отчасти Crystal, отчасти даже руби.
Да вот хоть джава (и как следствие, все шарпы): ни аспекты, ни рефлексия были бы невозможны, если бы об инструментарии не подумали сразу.
Понятно. Тогда вопросов не имею. Список говорит сам за себя.
А что именно он говорит, можно узнать?
Кроме джава перечислены "маргинальные" языки. Не в плохом смысле. Просто на этих языках сделано относительно мало проектов. Хотя те, что сделаны безусловно вызывают уважение.
А джава. Из-за требования сохранить совместимость с байт кодом у них дженерики, к примеру, получились ущербными.
Да и туллинга нет официального. То что есть, писаны с боку энтузиастами. И выстрадано кучей неудачных вариантов/поколений.
У УАЗа Буханка тоже сразу хорошо получилась.
Это у вас на превью Столяров что ли?
приятная статья, стимулирует понимание, imho с языками программирования произошла в общем обычная история, "за деревьями леса не видно", невольно вспоминается Zuse, само название "Plankalkul" примерно равно "formal system for planning", идея языка как инструмента программирования выражена с предельной точностью,
согласен с автором, что Erlang заслуживает большего внимания, min стоит посмотреть в сети обзорную статью Joe Armstrong "A History of Erlang"
Обосновывать отсутствие необходимости в чём-то тем, что без этого можно обойтись, - нечестный логический приём. Обойтись, в конце концов, можно много без чего, так мы и правда до машинных кодов скатываемся. То же ООП - просто способ структурировать функции и данные, и те же сами функции, безусловно, могут обрабатывать те же самые данные без всякого ООП. Все абстракции просто чем-то дополнительно помогают: или спасают от ошибок, или упрощают рефакторинг, или позволяют удобнее структурировать код.
Но все эти эффекты, безусловно, виднее на больших объёмах. Поэтому нужен нам тип/класс User или тип Password - логично было бы иллюстрировать не примитивным примером, а рассмотрев постепенно усложняющуюся систему. В которой сначала у нас простая табличка user-password, а в конце постепенно добавляется дюжина разных способов аутентификации, 2FA, минимальные требования к сложности/возрасту пароля, проверки его на дублирование/наличие в утечках и т.д. и т.п.
рассмотрев постепенно усложняющуюся систему. В которой сначала у нас простая табличка user-password, а в конце постепенно добавляется дюжина разных способов аутентификации, 2FA, минимальные требования к сложности/возрасту пароля, проверки его на дублирование/наличие в утечках и т.д. и т.п.
Процесс, который здесь описан, сам по себе ненормален. По целому ряду причин не надо делать систему защиты информации путём эволюции таблички user-password.
Ну ладно, это же просто «развитие» фактически навязанного мной в тексте примера. Предметная область совсем ни при чем, хотя рациональное зерно даже на таком примере можно увидеть: не нужно переусложнять предметную область, она сама справится себя переусложнить, без нашей помощи.
Ну да, в идеальном мире надо спроектировать всё-всё-всё заранее... и так и остаться в недописанным проектом, когда деньги закончатся :) Отвлечёмся от аутентификации, в этой сфере велосипедостроение чревато, привёл такой пример просто потому, что автор статьи его привёл. Но на стадии прототипа, а иногда и MVP, реализовать заглушку под последующее расширение функционала (которое в случае MVP по итогам запуска может понадобится, а может и нет) - совершенно нормально. И куда приятнее, если в этом случае не приходится переписывать код во всех тех сотнях мест, где мы зашили обычную строку вместо пользовательского типа.
в этом случае не приходится переписывать код во всех тех сотнях мест, где мы зашили обычную строку
Обожаю эти аргументы: если нет класса — наступит апокалипсис. Не наступит.
Во-первых, никто не предлагал ограничиться строкой, во-вторых, таких мест должно быть одно, а не сотня, и, в-третьих, если их сотня — никакие классы не помогут (а вот навредят — запросто).
Ваши аргументы пока что сводятся к "мне удобно так, значит всем остальным должно быть удобно так же и никак иначе".
У меня нет аргументов, защищающих мою точку зрения (точнее, они есть, но находятся за рамками данного обсуждения).
Мой тезис: классы усложняют предметную область (с ним бессмысленно спорить, «класс косточковые, вид сочные, экземпляр яблоко» сложнее объекта «яблоко»). Вопрос, сколько выгоды мы получаем от этого переусложнения. Я считаю, что выгоды нет.
Если вы считаете, что выгода есть — просто попробуйте не спорить со мной (это бессмысленно, «Наполеон всегда прав, если Наполеон неправ — см. п. 1»), а подумать и обрисовать себе самому эти выгоды. Не те которые вам продали авторы бесчисленных книжек за истину в последней инстанции — а те, с которыми вы лично увеличили свой КПД.
Да что ж Вы к классам-то привязались. Я вообще сейчас пытаюсь уползти с C# на Rust и в меньшей степени Go, где ООП весьма условное. Но у меня свой набор критериев выбора, которые кратко затронул в комменте ниже, которые специфичны для моих бизнес-задач и ничьих больше. У Вас свои. В отличие от Вас, я не пытаюсь представить их универсальными и переложить бремя доказывания обратного на весь остальной мир.
Мой тезис: классы усложняют предметную область (с ним бессмысленно спорить, «класс косточковые, вид сочные, экземпляр яблоко» сложнее объекта «яблоко»)
Т.е. вы именно что против наследования выступаете, а класс, это просто необходимый для наследования инструмент (и получается только для него)?
Я не выступают против наследования per se, я просто считаю, что сложные структуры данных, которые мало того, что позволяют прицепить к ним зачем-то и обработку оных, так еще и могут случайным образом дизъюнктировать свои потроха — неоправданное, ничего хорошего не приносящее, переусложнение.
Сами себе напридумывали систему типов - сами придумали, как обойти проблемы при её изменении - сами порадовались. Всё хорошо, только к производительному труду в интересах решения прикладной задачи это не имеет отношения.
.
Все абстракции просто чем-то дополнительно помогают […]
Моё (в данном вопросе не настолько уж и облыжное) мнение заключается в том, что этот тезис — маркетинговый булшит. Не помогают. Мешают. Увеличивают когнитивную сложность. Запутывают. Раздувают кодовую базу ради ничего.
логично было бы иллюстрировать не примитивным примером
Тогда бы текст не дочитал конца никто. У меня есть опыт разработки очень сложных систем. Чем проще (не побоюсь этого слова — примитивнее) инструментарий для этого используется — тем проще, быстрее и чище идет разработка (и отладка, и рефакторинг).
Я не сомневаюсь, что и описанную мной задачу Вы на своём любимом Erlang решили бы достаточно эффективным и элегантным способом. Увы, лаконичность статьи не позволяет понять, каким. А самостоятельно изучать Erlang и принятые в этом ЯП концепции проектирования систем я, к сожалению, не буду, т.к. выбор ЯП для проекта зависит от множества факторов, никак не связанных с концептуальной красотой самого языка :)
Но вот "когнитивная сложность" суть понятие сугубо субъективное. Для людей с математическим бэкграундом то же ФП кажется самоочевидным, для других же - отнюдь. Кому-то логично и естественно мыслить объектами, кому-то нет. Кто-то программирует на таком уровне, что не нуждается в подстраховке от глупых ошибок со стороны компилятора, а кто-то нуждается. И т.д. и т.п.
Я не предлагаю ничего изучать, я предлагаю подумать, только и всего.
выбор ЯП для проекта зависит от множества факторов, никак не связанных с концептуальной красотой самого языка
У меня лично только от этого и зависит.
У меня лично только от этого и зависит.
А большинству приходится думать ещё и о том, где и за какие деньги они найдут/обучат других пишущих на этом ЯП (и легко заменят их при необходимости), насколько код на данном ЯП легко понимаем другими программистами (либо он допускает такое многообразие стилей, которое этому препятствует), сколько уже написанного кода на этом ЯП (библиотеки/фреймворки/образцы кода) можно переиспользовать и т.д. и т.п.
А в свете последних тенденций так ещё и насколько хорошо код на этом ЯП генерируют LLM и насколько ЯП защищает от ошибок в том, что они там нагенерировали :)
Если бы мне хотелось думать о деньгах и найме, я бы открыл свой бизнес (и даже, наверное, стал бы зарабатывать немножечко больше).
Но хорошо, допустим.
Как вы думаете, какая зависимость простоты для понимания другим программистом от количества абстракций?
Насчет генерации кода LLM — это смешно. меня зовут решать задачи, которые ни одна LLM никогда и близко не решит.
Ну вот видите, какой Вы уникальный. Тем более, 100%, что то, что подходит Вам, не подходит всем остальным простым смертным :)
Про LLM тему развивать не буду, можно весь день в дискуссиях потратить. Конечно, ничего толкового она не напишет совсем сама, кроме одноразового кода. Но как инструмент в руках человека - работу ускоряет, и при этом, кстати, ибо человек ленив и может к результатам работы "помощника" отнестись недостаточно критически, - крайне полезно, чтобы ЯП был лаконичен, не допускал 1000 способов сделать одно и то же, а максимальное количество ошибок выявлялось компилятором... Но это вообще отдельная тема.
скорость разработки сложная метрика, скорость отладки более надежна, по опыту давно оцениваю уровень квалификации людей по тому как быстро отладку могут делать, причем чем сложнее система, тем это нагляднее
Отладка в однопоточном линейном коде и отладка в кластере из двадцати нод, на каждой из которых живёт 100К горутин/процессов — это два ортогональных навыка :)
Не факт, если вы в обоих случаях привыкли полагаться на print to stdout :)
Я привык полагаться на тесты и не испытываю нужды в отладке per se. Разве что, в метрики загляну.
Тесты упали. Тестовые сценарии корректные. Визуально код корректный. Наступает время отладки и тесты нет смысла трогать.
Ваши действия?
Если тесты написаны не для того, чтобы увеличить покрытие, а чтобы помочь разработчику, — они однозначно укажут на код, который не отработал. Я пойду и его поправлю.
Чудный мир сферических коней.
Рад, что хоть у кого есть возможность писать на erlang и имеет идеальные всепокрывающие тесты.
Завидую. За 25 лет в ИТ ни разу такого не видел.
Вы сами себе противоречите: если тесты упали (это ваше предположение, высказанное в предыдущем комментарии) — то проблемное место в коде понятно.
Если проблема проявляется на зеленых тестах — надо написать такой тест, который от нее покраснеет.
За 25 лет в ИТ ни разу такого не видел.
Бывает. Я тоже за первые 20 лет не видел.
Вы сами себе противоречите: если тесты упали (это ваше предположение, высказанное в предыдущем комментарии) — то проблемное место в коде понятно.
Нет, не противорчу. Кроме "тесты упали" я еще написал "Тестовые сценарии корректные. Визуально код корректный".
Другими словами да, тест упал. Но из кода не очень понятно почему именно он упал. Бывает и такое. И в этом случае наступает время отладки в том или ином виде.
Никогда не поверю, что имея на руках только структуры "списки, мапы, примитивы" всегда все будет по коду без необходимости в том или ином виде отладочной информации.
Я не миссионер, и никогда себя в этой роли не искал.
Но если вы попробуете себе представить акторную модель, изолированные процессы и полностью иммутабельное всё — вам, наверное, придет в голову мысль, что наведённых ошибок у нас фактически не бывает, только гонки, которые сравнительно легко локализовать и функции, которые покрываются юнит-тестами.
два ортогональных навыка ...
возможно
отладка в кластере из двадцати нод ...
современные embedded systems имеют сравнимый уровень сложности, если интересно посмотрите Ciena 6500-S32, типа сколько там процессоров, и как они должны взаимодействовать даже для одного шасси, которые на самом деле шлейфом тоже могут работать, + требования по времени реакции, нагрузке, hot swap, и т.д. , всем этим в той или иной степени приходилось заниматься, соответственно и отношение к квалификации программистов
Спорно, хотя ответ зависит от того, что понимать под "развитием". "Улучшение" существующего, возможно, и не требуется. А вот создание новых языков (или адаптация "хорошо забытых старых") окажется необходимым, как только появятся вычислители с другой архитектурой.
Строгая типизация — это то немногое, что функциональщики смогли продать объективистам.
Дочитал до этого места и несколько подвис. Вообще-то ООП – это изначально именно про типы, ничего тут "продавать" не нужно, и никакая функциональщина вообще ни при чём. Объектные языки с динамической типизацией – строго говоря, отход от канона и довольно серьёзный компромисс.
В конце концов, мы же как-то обходимся джейсоном для передачи «объектов» туда-сюда?
Обходимся – если других вариантов нет. А вот проектировать систему, повсюду гоняющую внутри туда-сюда JSONы я бы точно не стал. Хотя бы потому, что их нужно валидировать перед каждым использованием. Полноценно так валидировать: структуру, соответствие типов каждого поля, всё вот это вот. И конечно, каждый раз эти данные преобразовывать в нативное представление языка – дабы ими было можно как-то манипулировать. А потом обратно в JSON – чтобы передать дальше или вернуть результат. Что сразу привносит совершенно чудовищные накладные расходы, да и код прилично замусоривает.
их нужно валидировать перед каждым использованием
Зачем это еще? Почему на границе нельзя спарсить, а внутри периметра — уже просто использовать?
преобразовывать в нативное представление языка
Я абзаца три посвятил тому, что идеальное нативное представление языка именно такое: списки, мапы и примитивы. Всё.
код прилично замусоривает
Если делать что-то ненужное (как, например, создавать какие-то там объекты вместо готовых — бери и используй — данных) — то код да, замусоривается преизрядно.
Я как раз считаю, что этого можно избежать.
Зачем это еще?
Затем, что внутри системы происходит обработка данных – соответственно, либо эти JSONы меняются, либо порождают другие. В любом случае результат отличается от исходных данных и после преобразования а JSON требует валидации в точке использования.
идеальное нативное представление языка именно такое: списки, мапы и примитивы.
JSON не является ни тем, ни другим, ни третьим – это просто строка. Соответственно:
Если делать что-то ненужное (как, например, создавать какие-то там объекты вместо готовых
Если обмен данных между модулями системы построен на передаче JSON, никаких готовых объектов нет – есть их строковое представление, которое нужно преобразовывать туда и обратно. Именно это и есть ненужная работа.
Я нигде не предлагал внутри системы использовать строковое представление JSON, я предлагал использовать те типы данных, которые определены в джейсоне. Вот прямая цитата:
если все данные прекрасно описываются типами данных, разрешенными в джейсоне (строка, число, да/нет, список (массив), мап (dictionary, JSON object), null) — зачем нам лишняя когнитивная нагрузка в виде объектов? Чем экземпляр класса
User
лучше кортежа{name, password}
и набора функций, принимающих этот кортеж в качестве параметра вместоthis
?
Иными словами, объекты с методами и инкапсуляцией — лишняя и ненужная абстракция поверх списков, мапов и примитивов.
зачем нам лишняя когнитивная нагрузка в виде объектов?
Нам нужно уменьшение когнитивной нагрузки и автоматическая верификация кода. Например, если у меня есть класс
User {int id; String name;}
то опечатка user.mane
будет обнаружена ещё при написании кода, средствами IDE. В то время как если это мапа, то user['mane']
IDE проглотит не задумываясь. А ещё хуже, если кто-то сделает такую опечатку в данных самого юзера – и этот объект пойдёт гулять по коду, который ждёт поле name
.
Иными словами, объекты с методами и инкапсуляцией — лишняя и ненужная абстракция
Семантическая прозрачность весьма важна при написании кода. Если я вижу, что на вход поступает именно юзер, а не набитая неизвестно чем мапа, мне нужно гораздо меньше думать.
то опечатка
user.mane
будет обнаружена ещё при написании кода
Ну так в нормальных языках доступ к полям мапы так и осуществляется, привет.
Если я вижу, что на вход поступает именно юзер, а не набитая неизвестно чем мапа […]
Вы пропустили тот здоровенный кусок в тексте, в котором я говорил про теги, да?
Вы пропустили тот здоровенный кусок в тексте, в котором я говорил про теги, да?
Не пропустил, но как и, подозреваю, большинство читателей, я не имею никакого отношения к эрлангу, и скорее всего, никогда иметь не буду.
Ну так в нормальных языках доступ к полям мапы так и осуществляется, привет.
Вы что-то путаете. Map во всех её разновидностях – структура ключ-значение, которая заполняется в рантайме и на этапе компиляции/статического анализа не проверяема.
Какая связь между тегами и эрлангом, стесняюсь спросить?
стесняюсь спросить
Не надо стесняться. Всё просто: в известных мне языках такого понятия нет – соответственно, делаю вывод, что это особенность незнакомого мне, но пропагандируемого Вами эрланга. Ну или может, эликсира.
Я ничего не пропагандирую.
Я понял, вы не знаете, что такое тег. Бывает.
Я понял, вы не знаете, что такое тег. Бывает.
То есть ответов на мои вопросы нет, переходим в режим ad hominem. Бывает.
На какие еще вопросы? Ну-ка ткните-ка пальчиком, где вы вопрос задали?
Словосочетание «ad hominem» нельзя применять в качестве оправдания узости собственного кругозора, это не я, это вы заявили, что не знаете, что это такое.
где вы вопрос задали
Я поставил вопрос о том, что предлагаемый Вами подход неэффективен и потенциально ведёт к необнаруживаемым на ранних этапах ошибкам. Пока ни одного обоснованного возражения не прочитал.
это вы заявили, что не знаете, что это такое.
Да, и что? Это как-то доказывает Вашу правоту, или свидетельствует о том, что после этого со мной и обсуждать нечего?
Собственно, не настаиваю – представление в результате дискуссии получил, а что-то доказывать, убеждать мне не надо. Так что можем и завершить.
Так что можем и завершить.
Вот спасибо, век такой милости не забуду.
Так стоп, а мне уже интересно) Положили мы в словарик user["mane"], пытаемся где-то дальше достать user["name"], получаем что-то типа KeyNotFound. Чем это лучше доступа к user.name, проверяемого при компиляции? Уже молчу про то, что в user["age"] запишем name, а дальше попытаемся его в int спарсить.
Если у вас в программе захардкожен доступ по конкретному полю мапы (в данном случае 'name'), то скорее всего, вы что-то недодумали в абстракции. Это частный случай использования магических констант.
Если у вас в программе захардкожен доступ по конкретному полю мапы
У меня – не захардкожен. Ибо я мапы использую по прямому назначению – ни в коем случае не как замену фиксированным структурам. Если ещё точнее – мои программисты так делают, а я только отслеживаю, чтобы не хулиганили 🙂
Можете читать как "... по конкретному полю структуры".
Можете читать как "... по конкретному полю структуры".
Нет, так читать не будем. Ибо если у меня определена вышеупомянутая структура:
User {int id; String name;}
то ссылка user.name
– никакой не хардкод, и никаких констант для её использования определять не требуется. Вот в случае мапы да, можно:
const USERNAME 'name';
...
String un = user[USERNAME];
Только зачем?
то ссылка
user.name
– никакой не хардкод
В ваших понятиях, может быть, и нет, но для меня это точно такой же хардкод, как и user['name']
. Как Вы сами верно заметили, денотационная семантика здесь одинаковая, а отличается только операционная, то есть конкретные действия IDE и компилятора.
Как только вы подниметесь на определённую ступеньку абстракции, то там не останется никаких конкретных полей.
Как только вы подниметесь на определённую ступеньку абстракции, то там не останется никаких конкретных полей.
Примерчик можно? Как Вы получаете доступ к значению конкретного поля структуры, ни разу на само поле конкретно не ссылаясь? Прямо аж интересно – может, я что-то важное упустил в этой жизни.
Вывожу его из входных данных программы.
В первом приближении, примерно так:
(define (default-receiver alist function parlist)
(cond
((assq function alist) =>
(lambda (procentry) ((cdr procentry) alist function parlist)))
((core-function? function) (core-receiver alist function parlist))
(else #f)))
Это можно было бы в объектном языке назвать диспатчером, только этому диспатчеру не нужен собственно объект.
Вывожу его из входных данных программы.
Экзотично. Я не понимаю даже, на каком языке написан пример – не говоря уж о том, что он делает и как отвечает на заданный вопрос. Могу только отметить несколько очевидных моментов:
В отличие от простенького
user.name
этот код абсолютно нечитаем и с моей точки зрения попросту недопустим – если он заменяет элементарную операцию получения значения.Из примера абсолютно неочевидно, каким образом он получает доступ в заданному полю структуры, не указывая его в явном виде. Чисто теоретически и независимо от языка программирования, есть только два способа получить такой доступ: явной ссылкой на него или через рефлексию. Ну разве что ещё по заданному смещению в памяти. Какой используется у Вас и где то место в коде?
Входные данные – штука крайне ненадёжная, требует тщательной валидации. Если же эти данные должны содержать ещё и информацию о внутренних структурах программы, чтобы сообщить ей, из какого поля брать данные – то это просто трэш какой-то, Вы прибиваете внутреннюю реализацию к клиенту гвоздями.
Вкратце: не вижу ни ответа на свой вопрос, ни тем более, преимуществ Вашего подхода. Напишите мне, пожалуйста, коротенький пример получения имени юзера без использования ссылки на содержащее его поле структуры. Чтобы вот прямо заканчивалось чем-то вроде
print username
А есть какой-то язык, код на котором вам понятен?
Как можно всерьез что-то обсуждать в вопросах разработки и не узнать один из лиспов — для меня загадка. В моём мире такое невежество даже для джуна недопустимо.
В моём мире такое невежество даже для джуна недопустимо.
Может быть, это повод вернуться в реальный мир? Я на лиспе (одном из, явно не этом) писал в последний раз лет 40 назад. Было подозрение, что он, но уверен не был.
Только это всё неважно: какой бы ни была глубина моего невежества, представленный пример никак не демонстрирует возможности доступа к данным, не используя явной ссылки на элемент структуры, и все мои замечания остаются в силе.
Я узнал LISP в принципе, но в каком из них есть assq, используется какой-то default-receiver и т.п. - не в курсе, для такого надо спрашивать LLM. Ну и даже после этого разбирать этот код без объяснений, почему он именно такой тут - для данной дискуссии слишком мало смысла.
Я вам пишу именно о том, что если вы хардкодите получение конкретно имени пользователя, то это пример недостаточно продуманной абстракции. У пользователя есть и другие атрибуты, кроме имени, зачем вам хардкодить именно имя? Напишите обработку произвольного свойства. Тогда и ваш принт будет печатать не только имя, но и любое другое свойство структуры данных user, которое выберет пользователь программы. В ООП вам для этого действительно потребуется рефлексия.
Если я говорю: "Алиса, назови мне имя этого пользователя" или "Алиса, назови мне дату рождения этого пользователя", то это ведь одно и то же с точки зрения логики.
Входные данные – штука крайне ненадёжная, требует тщательной валидации.
Правильно, но это никак не отменяет их дальнейшее использование.
Юзер, например, может авторизоваться по юзернейму, может по номеру кредитной карты, а может по адресу электронной почты. Содержательной разницы-то никакой нет. Важно тут только то, уникальны ли значения атрибута в нашем домене.
"Алиса, я тот самый пользователь из Урюпинска".
Из примера абсолютно неочевидно, каким образом он получает доступ в заданному полю структуры, не указывая его в явном виде. Чисто теоретически и независимо от языка программирования, есть только два способа получить такой доступ: явной ссылкой на него или через рефлексию. Ну разве что ещё по заданному смещению в памяти. Какой используется у Вас и где то место в коде?
В примере нет структуры в вашем понимании, есть ассоциативный список (аналог map). Поэтому рефлексия в данном случае не нужна (хотя никто не мешает её использовать при надобности).
Конкретно,
(define (default-receiver alist function parlist)
определим функцию default-receiver от параметров alist, function и parlist таким образом:
(cond
в случае, если
((assq function alist)
в ассоциативном списке alist имеется свойство, соответствующее значению параметра function
=>
то это свойство мы обработаем
(lambda (procentry)
обозначив его здесь как procentry
((cdr procentry)
и вызовем код, представляющий собой значение этого свойства
alist function parlist)))
со всякими полезными параметрами, в том числе переданным нам списком параметров.
Ну и дальше разбираемся, что делать, если нет такого свойства.
Напишите обработку произвольного свойства.
Это ошибочная концепция, мне не нужна обработка произвольных свойств – только тех, которые предусмотрены бизнес-логикой. YAGNI. Причём я хочу, чтобы в коде было очень конкретно видно, что именно каждый его фрагмент обрабатывает.
В примере нет структуры в вашем понимании, есть ассоциативный список (аналог map).
Чтобы достать элемент из такого списка, есть только один способ: передать ему ассоциированный с данным элементом ключ. Таким образом мы снова приходим к тому же самому: опечатка в имени ключа, которая не отслеживается методами статического анализа, приведёт к нарушению работоспособности программы.
Так имя ключа в конечном итоге происходит из входных данных. Поэтому естественно, что оно не отслеживается методами статического анализа. Но почему оно должно привести к нарушению работоспособности программы?
"Извините, нет пользователей со свойством 'mane', попробуйте поискать по-другому".
Что касается принципа YAGNI, то он исходит из презумпции, что сценарии использования программы понятны до её разработки. Это удобное для кодировщика положение дел, но далеко не всегда реалистичное. Например, для большинства задач системного программирования бизнес-логика попросту неизвестна.
Скажу больше, даже когда вам кажется, что вы знаете бизнес-логику, это может быть досадным заблуждением. Чтобы не удаляться от нашего примера: вот почему, например, я могу логиниться на свой компьютер только по юзернейму (ну, ещё отпечатком пальца иногда)? Кто это и зачем за меня решил? Какие-нибудь бородатые хиппи ещё до моего рождения, а дальше все тупо за ними повторяют?
Извините, нет пользователей со свойством 'mane', попробуйте поискать по-другому
Это и есть нарушение работоспособности программы. Потому что 'mane' прислал другой модуль той же программы – ну опечатался человек, бывает. Или наоборот: прислали 'name', а у Вас в parlist
опечатка: 'mane'. А вот если мы работаем с обеих сторон со структурой User с заданным набором полей, то такая ситуация невозможна в принципе.
Что касается принципа YAGNI, то он исходит из презумпции, что сценарии использования программы понятны до её разработки.
Из этого исходит сама возможность начинать разработку. Как можно программировать, не зная, что требуется в результате? Эти знания могут уточняться, и даже очень сильно изменяться в процессе, но когда мы пишем код, всегда знаем, что именно в данный момент хотим от него получить.
Ну и возвращаясь чуть назад:
Если я говорю: "Алиса, назови мне имя этого пользователя" или "Алиса, назови мне дату рождения этого пользователя", то это ведь одно и то же с точки зрения логики.
Нет. Это абсолютно разные бизнес кейсы и должны обрабатываться отдельно. Простой пример: имя может быть открытой, а дата рождения закрытой информацией. И логика там в этом случае разная.
А вот если мы работаем с обеих сторон со структурой User с заданным набором полей, то такая ситуация невозможна в принципе.
Эта структура ведь не возникает по волшебству внутри вашей программы, а каким-то образом заполняется из исходных данных. Поэтому вы просто таким образом переносите диагностику ошибки времени выполнения, связанной с валидацией данных, в другое место программы.
Уж не буду спрашивать, что будет, если у структуры действительно есть поля и name
, и mane
.
Или наоборот: прислали 'name', а у Вас в
parlist
опечатка: 'mane'.
Ну вам же не мешает работать то, что в компиляторе C++ английское слово structure
ошибочно написано как struct
? Это в таком случае особенность лексики входного языка, а не опечатка.
Из этого исходит сама возможность начинать разработку.
"МарьИванна, нам бы ваши проблемы".
всегда знаем, что именно в данный моментхотим от него получить.
Однако это может быть не равно бизнес-требованиям.
Это абсолютно разные бизнес кейсы и должны обрабатываться отдельно. Простой пример: имя может быть открытой, а дата рождения закрытой информацией. И логика там в этом случае разная.
А у пользователя "Майор Пронин", допустим, имя может быть закрытой информацией, в отличие от пользователя "Вася Пупкин", и что из этого? Контроль доступа к информации и бизнес-логика – две никак не связанные между собой вещи. И на список свойств-то ещё и атрибуты ACL или мандатные метки повесить совершенно элементарно, а вот дискретизировать доступ к полям структуры вам будет сложнее.
Эта структура ведь не возникает по волшебству внутри вашей программы, а каким-то образом заполняется из исходных данных.
Неверно. Исходные данные тут вообще ни при чём. Я один раз описываю в коде программы структуру User
, которая имеет поле name
– и далее в любом месте программы, где эта структура используется, попытка обратиться к полю mane
подсветит этот код как ошибочный в IDE и не позволит ему скомпилиться. Если же имя поля передаётся строкой, как ключ ассоциативного списка – эта ошибка вылезет только в рантайме.
Уж не буду спрашивать, что будет, если у структуры действительно есть поля и
name
, иmane
.
Откуда они возьмутся? Когда я определяю эту структуру, я знаю, какие поля там необходимы, и ничего лишнего в ней появиться не может.
Ну вам же не мешает работать то, что в компиляторе C++ английское слово
structure
ошибочно написано какstruct
?
Простите, речь совершенно о другом.
Однако это может быть не равно бизнес-требованиям.
Может – если программист решил поразвлекаться вместо работы, или просто не понял эти требования. В обоих случаях его вскоре уволят.
Контроль доступа к информации и бизнес-логика – две никак не связанные между собой вещи.
Здрасьте, приехали.
И на список свойств-то ещё и атрибуты ACL или мандатные метки повесить совершенно элементарно, а вот дискретизировать доступ к полям структуры вам будет сложнее.
Чем сложнее-то? Про геттеры слышали что-нибудь? Да и атрибутов в структуру я могу набить сколько угодно.
___
Я в целом понимаю, в чём причина разногласий – если Ваш основной язык лисп, да ещё и в течение длительного времени – это очень сильно меняет картину мира. Мне несколько раз приходилось к нему возвращаться после длительных перерывов – и каждый раз требовалось несколько дней, чтобы заново въехать в эту парадигму. Это никоим образом не язык общего назначения, он предназначен для решения специфичного круга задач и многие вещи в нём решаются весьма нетрадиционными путями. Что совершенно не говорит о том, что остальные языки должны следовать такому же подходу, или о том, что он чем-то лучше. В частности, обсуждаемый кейс гораздо лучше решается в рамках объектной модели. Мапы и списки – очень плохая замена для стандартизованных структур данных. Увы, лисп ничего другого не предлагает.
У меня нет "основного языка".
Неверно. Исходные данные тут вообще ни при чём. Я один раз описываю в коде программы структуру
User
, которая имеет полеname
– и далее в любом месте программы, где эта структура используется, попытка обратиться к полюmane
подсветит этот код как ошибочный в IDE и не позволит ему скомпилиться
Очень хорошо, но откуда вы берёте значение этого поля name и как понимаете, что это именно name?
Откуда они возьмутся? Когда я определяю эту структуру, я знаю, какие поля там необходимы, и ничего лишнего в ней появиться не может.
Вы считаете лишним любое поле, лексически похожее своим именем на другое? Например, поле maxValue будет лишним, если есть minValue? Или вы считаете, что по ошибке ввести maxValue вместо minValue невозможно?
Чем сложнее-то? Про геттеры слышали что-нибудь?
Так вы прямо в код геттера собираетесь захардкодить привилегии доступа? Или всё же создать отдельную структуру данных, содержащую ACL, являющийся по форме тем самым ассоциативным списком, от которого вы собирались избавиться?
Очень хорошо, но откуда вы берёте значение этого поля name и как понимаете, что это именно name?
Странный вопрос. Я пишу программу, которой по логике необходимо получить имя юзера. Я знаю, что это значение лежит в User.name
. Что ещё тут нужно понимать?
Вы считаете лишним любое поле, лексически похожее своим именем на другое?
При чём тут вообще это? Речь об опечатках, которые в одном случае со 100% гарантией предотвращаются, а в другом выявляются только в рантайме.
Так вы прямо в код геттера собираетесь захардкодить привилегии доступа?
🤦♂️ Ну зачем же сразу в глупости-то меня обвинять?
enum Privilege {private, public}
...
class ACL {
static Privilege name = public;
static Privilege dob = private;
}
...
class User {
String name;
Date dob;
const String denied = "access denied";
String get name =>
ACL.name == Privilege.public ? name : denied;
Date get dob =>
ACL.dob == Privilege.public ? dob : denied;
}
Годится? Можно развить как угодно – например, добавить проверку привилегий залогиненного юзера, и если он админ, показывать всё.
UPD:
Кстати, у меня в коде баг – на который IDE мне тоже, несомненно, указало бы 😁
Я и без IDE по вашему коду вообще не понимаю, в каком отношении находятся между собой классы ACL и User.
Но когда вы правильно всё распишете, то в ACL у вас окажется такой же список свойств, как тот, с которым вы решили бороться.
Странный вопрос. Я пишу программу, которой по логике необходимо получить имя юзера. Я знаю, что это значение лежит в
User.name
. Что ещё тут нужно понимать?
А тут нужно ещё понимать, каким образом оно оказывается в User.name
.
Я и без IDE по вашему коду вообще не понимаю, в каком отношении находятся между собой классы ACL и User.
Тут ничем не помогу – более очевидный код мне сложно себе представить.
в ACL у вас окажется такой же список свойств, как тот, с которым вы решили бороться
Нет, потому что у меня доступ к значениям не по строковым ключам, а по именам полей – обращение к несуществующему полю невозможно.
А тут нужно ещё понимать, каким образом оно оказывается в
User.name
.
Зачем? Этому фрагменту кода совершенно не нужно.
Тут ничем не помогу – более очевидный код мне сложно себе представить.
Нет, потому что у меня доступ к значениям не по строковым ключам, а по именам полей – обращение к несуществующему полю невозможно.
Я, наконец, понял! Вы просто захардкодили привилегии доступа к полям в класс с именем ACL (хотя это совсем не ACL). Так не делается в защите информации.
Но я-то имел в виду совсем другое. Сделайте так, что у пользователя с name="Pronin" привилегии есть, а у пользователя с name="Poopkin" привилегий нет.
Я, наконец, понял! Вы просто захардкодили привилегии доступа к полям в класс с именем ACL
Неа, ничего Вы не поняли. Например, я ведь писал:
Можно развить как угодно – например, добавить проверку привилегий залогиненного юзера, и если он админ, показывать всё.
Это прямой ответ на
Сделайте так, что у пользователя с name="Pronin" привилегии есть, а у пользователя с name="Poopkin" привилегий нет.
То же самое с "хардкодом" ACL – в реальном проекте нет ничего легче, чем заставить его читать список привилегий из конфигурации в базе. Но согласитесь, не буду же я здесь целый проект выкладывать. Включите воображение, додумайте хотя бы совсем уж очевидные вещи.
Так я это додумал ещё в самом начале беседы, как раз на что вы и взялись возражать, и всё никак не поспеете за тем, что я написал в самом начале. Как только вы запрограммируете чтение привилегий из конфигурации в базе, то это и будет ассоциативный список с неизвестными заранее ключами (ключом в данном случае будет являться строка "Poopkin" или "Pronin").
Как только вы запрограммируете чтение привилегий из конфигурации в базе, то это и будет ассоциативный список с неизвестными заранее ключами
🤦♂️ Да что ж Вы такое пишете-то.... Почему?! Это будет User.role
– которое, в свою очередь, нечто вроде
enum Role {guest, basic, premium, admin}
Поразительно.
Как у вас будет описываться список пользователей? И как будет выглядеть таблица в базе?
Там, куда вы, кажется, подталкиваете оппонента, замаячила пропасть внесения правок для идентификации по отпечатку пальца…
Как у вас будет описываться список пользователей?
List<User> users;
или возможно, с ключом юзер ид из базы, не знаю:
Map<int, User> users;
При чём тут это? И вообще, мы тут что, полную систему проектируем? Причём в ситуации, когда
бизнес-логика попросту неизвестна.
Я так не умею. И базы проектировать, не зная, для чего – тоже. Что я знаю точно – в хорошо спроектированной системе строковые ключи нужны крайне редко, и их нужно по возможности избегать.
(Оказывается, тут дискуссия шла ещё в одной ветке)
Так имя ключа в конечном итоге происходит из входных данных.
У нас данные соответствуют какой-то схеме. Они не могут не соответствовать, иначе их невозможно обрабатывать. Каким образом будет имя ключа для имени пользователя поступать во входных данных и, главное, зачем?
Посмотрите, например, на форму ввода в логине на Хабр. Там, условно говоря, слева выбирается метод аутентификации (функцией от этой галки является имя ключа для этого метода), а справа - само значение ключа.
Если вы аутентифицируетесь, скажем, через Vk, то у вас может не быть свойства name.
Не так важно в данном обсуждении, есть свойство name или нет. Оно может законным образом отсутствовать. Оно может быть разделено на несколько имён разного типа (как Ф, И, О или первое, второе, среднее, последнее). Важно, что оно, если есть, оно в поле (или под ключом) name
, а не nomen
, імʼя
или mane
. Именно об этом речь, а ваши возражения выглядят как прямая попытка увода дискуссии куда-то в неадекватную сторону.
Не так важно в данном обсуждении, есть свойство name или нет. Оно может законным образом отсутствовать. Оно может быть разделено на несколько имён разного типа (как Ф, И, О или первое, второе, среднее, последнее).
Это первостепенно важно, потому что именно об этом я и говорю. В нормативном акте написано "фамилия, имя и отчество", вот мы и анализируем свойства "фамилия", "имя" и "отчество". Будет другая ситуация – будут другие свойства. А не так, что прибитое гвоздями к объекту именно поле name.
Удивительное утверждение. Наверно, вы найдёте и достаточные аргументы в его пользу? 😲
Как быть в случае, когда использование имени, или даты рождения, или места жительства, или ещё чего-то - это бизнес-требование?
(UPD: можно продолжить в более глубокой подветке, или тут.)
А можно привести пример такого бизнеса, которого эти требования? Обычно в нормативно-правовых актах не указывается точный состав ключей, и это как раз произвол погромистов.
И вся фигня начинается, когда у человека, допустим, нет отчества, а захардкожено, что оно требуется.
А можно привести пример такого бизнеса, которого эти требования?
Хоть банк. Для клиента - физлица или ФЛП пишутся фамилия, имя, отчество. Для простоты мы тут говорили про одно name, даже если их три или больше.
Обычно в нормативно-правовых актах не указывается точный состав ключей, и это как раз произвол погромистов.
Без этого "произвола" не будет адекватного представления, сохранения и передачи данных.
И вся фигня начинается, когда у человека, допустим, нет отчества, а захардкожено, что оно требуется.
Это уже другой вопрос. Как рядом уже писал, отсутствие какого-то компонента нормально, если это описано схемой. Но если вам вместо ключа patronymic
придёт отчество
или по-батькові
, это не должно быть принято как допустимое. И наоборот. И то, что слово patronymic
тут "магическая константа" (ц), это не просто можно, это нужно.
Хоть банк. Для клиента - физлица или ФЛП пишутся фамилия, имя, отчество. Для простоты мы тут говорили про одно name, даже если их три или больше.
Заметьте, что даже фамилия, имя и отчество не идентифицируют клиента. У банка запросто может быть десять Иван Иванычей Ивановых в клиентах. А какие же поля идентифицируют? А хрен его знает, зависит от ситуации. А ещё может прийти исполнительный лист на Иван Иваныча Иванова, и будет из этого листа не очень понятно, о каком Иван Иваныче идёт речь. И вся ваша стройная схема тут порушится, потому что данные в реальном мире обладают свойством неполноты, а иногда и противоречивости.
Я как-то уже рассказывал, что был одновременно клиентом двух интернет-провайдеров, которые в какой-то момент слились в экстазе (то есть Ростелеком поглотил Сигму). А случилось так, что у одного провайдера про меня было прописано отчество "Евгеньевич", а у другого – "Евгениевич". И всё навернулось нахрен. Хотя с точки зрения аккуратного анализа речь идёт всего лишь о том, что у одного и того же клиента есть свойство "отчество" и свойство "отчество по данным другого провайдера", причём предусмотреть это удвоение учётных данных в момент написания и компиляции кода было нельзя. Но если б использовались нормальные динамические списки свойств, то никакой проблемы бы не возникло.
(Некоторые вот фамилию меняют при замужестве, и оказываются в подобной ситуации даже и без ошибок при вводе).
Заметьте, что даже фамилия, имя и отчество не идентифицируют клиента.
Замечу. Даже в изначальном примере рядом с name
был id
.
Но если б использовались нормальные динамические списки свойств, то никакой проблемы бы не возникло.
Это единственное в вашем ответе, что не заслуживает ярлыка "кэпство и оффтопик". Что ж, прошу показать, как именно подобные динамические свойства могут работать в реальном мире, и что будет вместо фиксированного имени поля или ключа в таком случае. Кажется, это тянет на отдельную статью.
В реальном мире это работает вот как:

По-моему, именно тут всё предельно ясно.
Надеюсь, понятно, что нигде в коде файндера нет переменной struct
, прямо вот хардкодно содержащей поля aperture
и iso
для файлов.
Надеюсь, понятно, что нигде в коде файндера нет переменной struct, прямо вот хардкодно содержащей поля aperture и iso для файлов.
Надеюсь, понятно, что эти критерии поиска откуда-то взяты и там они записаны как текстом, так и правилами извлечения из файлов.
Всё верно. Типовой является ситуация, когда значением какого-то свойства в ассоциативном списке является лямбда.
Однако плагин для разбора EXIF не является частью логики Файндера в целом.
является лямбда.
Какие у неё аргументы? Какой тип результата? Как она представлена в этом списке, под каким ключом? Какие условия для её вызова?
Однако плагин для разбора EXIF не является частью логики Файндера в целом.
Однако, он подключается каким-то стандартным API.
Аргумент объект (в данном случае файл), и результат объект (в данном случае значение диафрагмы или пусто). Ну или список, как уж там в языке представляется. Что вы как маленький.
Под каким она ключом представлена в списке, я не знаю, не я ж эту настройку файндера прописывал. Но ясно, что там есть свойство "displayName" со значением ассоциативного списка языков, у которого ключу "RU" соответствует "Диафрагменное число", и свойство "getValue" в виде этой лямбды, которая по файлу получает значение поля из EXIF, используя мемоизируемую функцию getExif(object).
Конечно, вы можете в порядке полемики заявить, что имя свойства "getValue" или "displayName" тоже являются магическими константами. Но это такие константы, которые если изменить, то вообще всё в программе перестанет работать. Это, можно сказать, фундаментальные физические константы, а не магические.
Если вы скажете, что это по существу таблица виртуальных методов, то будете правы. Только это таблица виртуальных методов, расширяемая в рантайме.
Однако, он подключается каким-то стандартным API.
eval().
Но ясно, что там есть свойство "displayName" со значением ассоциативного списка языков, у которого ключу "RU" соответствует "Диафрагменное число", и свойство "getValue" в виде этой лямбды, которая по файлу получает значение поля из EXIF, используя мемоизируемую функцию getExif(object).
И в результате выбор действия перевален на пользователя. Это работает в случае меню Finderʼа, согласен. Но это не работает в подавляющем большинстве случаев, когда именно программе надо понимать, в каком случае и как надо работать с id, в каком с name, в каком с first_name, и так далее.
Если вы скажете, что это по существу таблица виртуальных методов, то будете правы. Только это таблица виртуальных методов, расширяемая в рантайме.
И чего не делается в 99+% кода, ибо избыточно и непонятно, как с ним работать.
eval().
Вижу, я зря надеялся на конструктив.
И в результате выбор действия перевален на пользователя.
Не обязательно на пользователя, может быть на людей, ответственных за сопровождение программы.
Вообще, перемещение разных вопросов с фазы разработки на фазу сопровождения – полезно по целому ряду причин.
Это работает в случае меню Finderʼа, согласен. Но это не работает в подавляющем большинстве случаев, когда именно программе надо понимать, в каком случае и как надо работать с id, в каком с name, в каком с first_name, и так далее.
Можно привести конкретный пример, когда именно в программу это целесообразно захардкодить? Я вам привёл свой конкретный пример, приведите и вы мне свой.
И чего не делается в 99+% кода, ибо избыточно и непонятно, как с ним работать.
В 99% кода много чего не делается, начиная от обработки ошибочных ситуаций и заканчивая документированием. Это, однако, не повод рекомендовать для профессиональных программистов практики, принятые промеж невзыскательных кодогенераторов – в лучшем случае вкатившихся в IT за месяц неофитов, а в худшем – механических болванов LLM.
eval().
Вижу, я зря надеялся на конструктив.
Что вам тут кажется неконструктивным? Мой ответ может вас не устраивать, но это реальный ответ на ваш вопрос.
Можно привести конкретный пример, когда именно в программу это целесообразно захардкодить? Я вам привёл свой конкретный пример, приведите и вы мне свой.
Их миллионы вокруг, этих примеров. Учёт персонала или клиентов: ФИО, как уже обсуждалось (нулевая длина одного компонента не мешает). Счета согласно стандарту и плану счетов, приходы-расходы со счётом, банком и причиной в стандартном формате. Случаев, когда формат данных фиксирован и не требуются дикие изыски (или они просто недопустимы), на порядки больше, когда допускается какая-то супергибкость. И прочая и прочая. Можно не рассматривать чисто внутренние программные интерфейсы, но и в них тоже. И это не просто фактично, это правильно - иначе мы бы все утонули в ненужной сложности. Умение избавиться от громоздкой избыточности и сделать успех через простоту - важнее умения навести гибкость, это как раз умеет "вкатившийся в IT за месяц", по вашим же словам.
Это, однако, не повод рекомендовать для профессиональных программистов практики, принятые промеж невзыскательных кодогенераторов – в лучшем случае вкатившихся в IT за месяц неофитов, а в худшем – механических болванов LLM.
Отличный пример некорректной дискуссии. Сохраню не за идею - в ней нет ничего нового - но за слог.
Учёт персонала или клиентов: ФИО, как уже обсуждалось (нулевая длина одного компонента не мешает). Счета согласно стандарту и плану счетов, приходы-расходы со счётом, банком и причиной в стандартном формате.
Окей, принято. Давайте посмотрим, какие самые распространённые и коммерчески успешные программы для выполнения этих функций существуют в настоящее время. Очевидно, 1С в России и R/3 в мире (ну, можно ещё вспомнить всякие Oracle Applications и т.д., но они картины не меняют). И что же, номера счетов и ФИО зашиты в 1С или R/3? Конечно, нет. Программа запускает eval(), чтобы выполнить скрипт пользователя, и не более того. А номера счетов прописывает уже сам пользователь или внедренец в своём скрипте (то есть, говоря теоретическим языком, лямбде). Да и было бы очень странно, если бы приходилось переписывать R/3 из-за того, что изменился план счетов в бухгалтерском законодательстве Зимбабве.
Так что ваш пример совершенно чётко работает в мою пользу.
Давайте посмотрим, какие самые распространённые и коммерчески успешные программы для выполнения этих функций существуют в настоящее время. Очевидно, 1С в России и R/3 в мире (ну, можно ещё вспомнить всякие Oracle Applications и т.д., но они картины не меняют).
Спасибо, я так и знал, что ответ придёт к этому :)
1) Вы выкинули остальные примеры... уже, наверно, показательно.
2) Про какую-то "самую распространённость" 1С и R/3 я бы не говорил. Самое распространённое это сейчас всякие клиент-банки и системы микроплатежей. Включая системы типа WeChat. Там не делают гибкости в наборе характеристик, там другие задачи. Иначе оно просто не выдержит нагрузки.
То же относится к "сердцу" всех финансов - почитайте коллегу SpiderEkb@, например, как они пишут код на всяких RPG.
А монстры, которых надо месяцами настраивать - они где-то посредине, где деньги [почти] не считают.
3) Вы криво прочли (кажется, я криво описал) - сам план счетов, конечно, где-то задаётся в конфигурации, он не важен тут. А вот состав ходящей информации при переводах - он как раз фиксирован, задан законодательством или стандартом платёжной системы. И на нём как раз излишней гибкости обычно не делают, хардкодя состав и роль полей.
Так что ваш пример совершенно чётко работает в мою пользу.
Аж никак нет:)
Вы выкинули остальные примеры... уже, наверно, показательно.
Что я выкинул? Я Вас попросил дать конкретный пример по Вашему выбору, Вы написали, я на него ответил.
Про какую-то "самую распространённость" 1С и R/3 я бы не говорил. Самое распространённое это сейчас всякие клиент-банки и системы микроплатежей. Включая системы типа WeChat. Там не делают гибкости в наборе характеристик, там другие задачи. Иначе оно просто не выдержит нагрузки.
Клиент-банки и системы типа WeChat просто являются браузерами для активного контента. Там вообще прикладной логики ноль.
То же относится к "сердцу" всех финансов - почитайте коллегу SpiderEkb@, например, как они пишут код на всяких RPG.
Коллега @SpiderEkb находится в специфической ситуации, когда ему надо выжимать микросекунды. Поэтому, естественно, он оптимизирует программы по максимуму, платя трудоёмкостью за процессорное время. Он бы и на ассемблере писал, если б был ассемблер для IBM i. Это очень уважаемая, но не обычная ситуация.
(вдогонку) Но вообще я бы именно что "статистически" сказал, что да, любую возможность согнуть в сторону, которую вы описываете тут - используют в полный рост. И именно это чуть ли не главная причина прожорливости нынешних приложений. Например, вместо честного локального гуя (пусть и через универсальную библиотеку) - Electron как подложка. Интерпретаторы HTML, JS, CSS и "eval" "лямбд", в ваших терминах, которые занимаются всей отрисовкой.
И мы все платим за эту избыточность, которая в большинстве случаев не нужна. И поэтому я признаю её возможность использования, да, где это на пользу - но сам набор таких случаев, когда это на пользу, резко меньше тех, где это оправданно.
идеальное нативное представление языка именно такое: списки, мапы и примитивы. Всё.
Для этого даже ругательство придумано - PHP-стиль :) когда по коду передаётся прсто мапа и удачи предсказать какая у нее будет структура, и когда и кем значения по каким ключам меняется.
Без нормальных структур это боль, а не программирование. Хотя я отчасти согласен - ООП в его академическос понимании создаёт проблем больше, чем их решает.
Без нормальных структур это боль, а не программирование.
Мой опыт говорит об обратном.
по коду передаётся прсто мапа и удачи предсказать какая у нее будет структура
Эрланг и эликсир полностью иммутабельны, хоть упередавайся — изменить не получится. Это решает примерно 102% проблемы.
дело не в том, что я хочу поменять что-то в мапе, а в том, что структура этой мапы не специфицирована.
Почему не специфицирована? Очень даже специфицирована, если надо. Экспортируйте функцию createUserMap
, тегните её как-нибудь, как я рассказывал с тексте (например, при помощи ключа __struct__
, как это делает эликсир) — и вот вам спецификация, какие проблемы-то?
Поздравляю, вы изобрели структуру :)
Да и Elixir сам так и говорит, что в их понимании Map - это key-value data-structure.
Если же говорить о каком-нибудь другом языке, то у них map и структура могут быть разными сущностями.
Ваша статья после ваших комментариев преобретает немного другой вид - ощущение, что вы не про "развитие" языков говорите, а хотите чтобы все языки стали похожи на ваш единственный и любимый.
Буду рад если это мне только показалось.
Я ничего не изобретал, всё изобрели до меня.
Если же говорить о каком-нибудь другом языке, то у них map и структура могут быть разными сущностями.
Угу. Я про это и писал. Ровно про это. Разные сущности, а поверх — еще классы. Ради ничего.
Я про это и писал. Ровно про это. Разные сущности, а поверх — еще классы. Ради ничего.
Знаете, я только рад, что в программировании изобрели ООП, хотя это и не самый лучший подход.
Почему? Нет ничего идеального. Все эти попытки что-то изобрести, они двигают вперед программирование. И это прекрасно. Это эволюция и наблюдать за ней - удовольствие.
Также это прекрасно, что есть возможность выбора и смотреть на проблему с разных сторон. Например одну и ту же задачу/проблему можно совершенно по разному решать на разных языках и наоборот - один вариант решения бывает физически невозможно реализовать на каком-то конкретном языке.
Со своей стороны я разделяю языки на те, что приносят удовольствие и те, что приносят деньги. И то, что это (в моем случае) не пересекающиеся области не сильно меня смущает.
Заслуга ООП хотя бы в том, что оно показало, что, в итоге этот подход не решает поставленных перед собой задач.
Точно также Erlang показал, что каким бы математически выверенным не был язык - это тоже не панацея. Правда где-то посередине. И я не верю, что какой-то один язык сможет нащупать и реализовать эту золотую середину так, что остальные языки окажутся неудел.
Но наблюдать за всем этим - очень интересно!
В эрланге нет ничего математически-выверенного. Вообще (ну почти вообще).
Разница между нами в том, что я прекрасно знаю, и в теории, и на опыте, как работает ООП, как работает ФП, и как работает акторная модель. И почему WhatsApp написан именно на эрланге, и почему в 90% роутеров используется именно эрланг. И причина — не выверенность. А простота.
И причина — не выверенность. А простота.
Вынужден не согласиться с вами.
Дайте определение термину - простота.
Может быть это размер спецификации языка? Количество задействованных ключевых слов? Или количество структур данных?
Причины почему Erlang используется в сетевых приложениях "получи-передай" не в простоте, а в гарантиях дающие его компилятором и средой исполнения.
Гарантиях, что данные в структурах не мутируют, гарантии, что память будет очищена автоматически, гарантии, что систему типов не обмануть и так далее.
Назвать Erlang простым - ну такое. Любители Python и JavaScript с вами бы поспорили :)
И почему WhatsApp написан именно на эрланге
Потому что экспериментировали - и потому что для сервера-раздатчика с небольшим входящим потоком и обменом на среднем уровне "пара сообщений в час" он вполне подходит.
А вот если бы каждый пользователь WhatsApp слал новое сообщение хотя бы раз в три секунды, эрланг бы подох, не сумев отшедулить всю эту массу объекто-серверов по одному на пользователя.
и почему в 90% роутеров используется именно эрланг.
Это уже обсуждали - Erlang где-то там сбоку припёка на конфигурационных функциях (даже в исходном AXD301 было где-то так же, область применения по сути не расширилась). Тут позиция "не упадём и потому не утащим за собой собственно раутинг, даже если конфигуратор что-то не осилил" - самое оно. Но и тут что Go, что Java, что ещё десяток альтернатив подошли бы не хуже.
Каждый раз когда мне пытаются продать новый или старый идеальный язык я иду смотреть вакансии. И по Erlang/ Elixir в России всё плохо. На Rust / Java / Go / C# хотя бы будет хлеб с маслом и иногда с икрой. А уж на 1С (в текущем моменте) тем более.
PS Elixir имеет нормальный синтаксис. При наличии удобного IDE я бы мог, а толку...
Я никому ничего не пытаюсь продать, это во-первых. Мне лично нужна всего одна работа, а не триста, поэтому список вакансий тут не пришей кобыле хвост. И, в-третьих, хорошая работа должна приносить радость и удовлетворение, а ради прокорма я мог бы и поваром устроиться.
Мне лично нужна всего одна работа
Рисковый вы человек. Мне, как семейному, ближе стабильность и понимание того, что случись что с компанией где я сейчас работаю - смогу быстро найти другую не сильно изменяя стеку/технологиям.
Поэтому мне лично нужно больше одной компании, внезапно.
Дело даже не что вакансий мало. Платят мало (
Лично мне Erlang нравится больше Elixir.
А вот задач для них, действительно, увы - именно потому, что отцы-основатели застыли тупыми блоками бетона в концепциях ровно уровня диссера Армстронга и не дальше.
Ну такое.
Иногда конечно хочется вернуться в чистые пруды простоты и первородства, писать красоту и не волноваться.
Но тогда уж лучше байтики складывать на сях.
Где в json-ках простота я вижу, но вот где удобство - совершенно нет.
Типизация нам не просто так дадена. Она отсекает целый пласт ошибок и даёт мощнейшие инструменты как для выразительности, так и для ограничений, кои нужны. Особенно иронично звучит отказ от нее, если вы пишете тесты и практикуете TDD - тесты писать не лень, а главный и простой тест по спецификациям - лень.
Как по мне красота и мощь как раз не в ограничении на минимум типов, а в возможности писать свои. Как функции пишутся из последовательности команд, так и сложные типы из композитов.
Вызывает грусть пухнущее функциями и сложностью ПО, и наверное было бы хорошо, если бы мы научились не только добавлять, но и удалять. Но не так это должно решиться
Я довольно подробно объяснил, почему строгая типизация без завтипов — никому не нужная игрушка для детей, маркетинговый булшит, который массовый рынок употребил и не поперхнулся.
Про мою лень… ну не поняли вы текст — это нормально. Я не в обиде, я не лемма Пуанкаре, чтобы быть всем понятным, да и не рассчитываю на масс-маркет.
Я довольно подробно объяснил, почему строгая типизация без завтипов
Обратимся к тексту:
Типы могут принести очень много пользы, если они «граждане первого сорта». Ни в одном более-менее распространенном языке, кроме авангарда типа Coq/Rocq, Agda и Lean, и не покидающего стадию пре-альфа Idris, — нет зависимых типов. Строгая типизация без завтипов — детская игрушка.
Подробного объяснения нет, один наброс.
строгая типизация без завтипов
Насколько я понимаю, зависимые типы проверяются в компайл-тайме. Тогда вопрос, а языки с строгой типизацией без компайл-тайма (например, python) вообще не имеют права на существование?
JSON - это ублюдок, ставший стандартом "де-факто". Потому что кто-то когда-то додумался до того, что "зачем что-то парсить, валидировать, и т.д." - когда можно сделать eval - и вот - готовый "объект". Сколько уязвимостей это в свое время породило - страшно вспомнить. Это при том что был XML, схемы (как раз для валидации), XSLT для его трансформации хоть в чёрта лысого, и самой технологии было уже сто лет. Но кому-то пришла идея: зачем какие-то парсеры, схемы, валидация, херак eval - и хоба - объект!
Вы сказать что-то хотели по существу, или пар выпускаете? Мне XML тоже больше нравится, дальше-то что? Я ж не предлагал использовать джейсон, я всего лишь сказал, что типов, доступных в джейсоне — достаточно.
Действительно, зачем нам большие целые числа, зачем нам дата, зачем нам время, зачем нам интервалы, зачем нам продолжительности, зачем нам множества, зачем нам не строковые ключи в словарях, зачем нам стабильный порядок ключей в словарях, зачем нам картинки, зачем нам видео, зачем нам регулярки, зачем нам функции, зачем нам графы, зачем нам матрицы...
Это всё прекрасно реализуется в сторонних библиотеках (кроме функции, которая приходит как особый тип данных, ортогональный «статичным» в любом языке программирования и стабильного порядка ключей в словарях, который ярко демонстрирует проблемы с дизайном у автора кода).
Еще есть действительно важные типы, которых в джейсоне нет, и без которых не жизнь в нормальном языке: идентификатор процесса и UUID, но даже их, в принципе, можно реализовать поверх существующих.
Это всё прекрасно реализуется в сторонних библиотеках
как пример - удачи вам подружить разные библиотеки если они для той же даты разное ISO используют (подсказка, не все библиотеки позволяют задавать формат даты).
идентификатор процесса
Три числа через точку, у которых главное - что при переходе по межнодовому соединению часть компонентов (кажется, только первый?) может меняться?
Ну, "такое". Если бы сразу генерировали, например, в виде UUIDv1 с рандомом на месте MAC, получилось бы то же самое, но без необходимости конверсии. Главное, что его вредно запоминать в долговременном.
UUID
Текстовая строка, бинарь в 16 байт, на выбор. Важно только единообразие сериализации. И, что важнее к данному разговору, есть масса эквивалентов для всех случаев.
Итого - оба ни о чём.
стабильного порядка ключей в словарях, который ярко демонстрирует проблемы с дизайном у автора кода
Не у автора кода, а в когнитивных способностях человека, которые начинают проявляться в случае сверки данных (при отладке, верификации, да когда угодно). И снова у вас приступ верхоглядства с игнорированием сути.
Три числа через точку
Да как угодно, какая разница, как именно? Я просто сообщил, что без такого типа — вся строгая типизация рассыпается на костыли в кластере.
у которых главное — что при переходе по межнодовому соединению часть компонентов (кажется, только первый?) может меняться?
Я не знаю, что такое «переход по межнодовому соединению», но смысл такого типа в эрланге заключается в том, что по идентификатору процесса вы всегда можете узнать, на какой ноде процесс запущен, а также всегда можете с ним обращаться, как с локальным, например — использовать в качестве ключа в мапе на ноде1, получать по этому ключу значение с ноды2, а сам процесс может быть запущен на ноде3. Хотя все три значения пида в отладчике будут разными, удаленный вызов Map.get(pid)
отработает, как ожидается.
Главное, что его вредно запоминать в долговременном.
Не вредно, если руки растут из нужного места, и пишущий код нуждается в получении обновлений при крашах процесса. Супервизоры, на которых зиждется OTP, запоминают пиды, и всё прекрасно работает.
Важно только единообразие сериализации.
Если мыслить в категориях одной ноды — то да, конечно. Если требуется кластер — то нет, конечно.
Итого — оба ни о чём.
Пока только ваше представление о том, что они такое вообще — ни о чём.
в случае сверки данных (при отладке, верификации, да когда угодно)
Сериалайзеры/декораторы отменили? Хранить мап с упорядоченными ключами — это абсолютный маразм. Ради дебила, который не может правильно декорировать его при отладке, давать инструмент, который другой дебил завтра воткнет в код с ожиданиями — нелепость.
Блин, ну это не вина JSON, он то не плох.
Это вина eval, сам подход порочен.
Претензии к нему есть, но есть ли у вас лучше сопоставимые форматы?
И не является ли эта проблема проблемой Json или скорее проблемой JS, который представляет собой расхлябаное нечто в смысле типизации?
Если не требуется "человекочитаемость" - а она что в JSON что в XML весьма условна (про то что можно "посмотреть и поправить что угодно хоть в notepad" - ну такое...) для реально больших ПОТОКОВ данных - это преимущество так себе) - то Protobuf хотя бы.
Нужна ли современному языку программирования общего назначения производительность? — Нет.
У нас есть си, для микроконтроллеров, зубодробительной арифметики и прочего нишевого использования. Си прекрасно справляется со своей задачей.
Игры к примеру тоже на Си писать или там не нужна производительность?
виртуальная машина не сделает софт настолько медленнее, что от него придется отказаться в пользу компилятора в нативный код
Забавно что буквально недавно Майки переписали компилятор TS на Go. А еще недавно статья была как компилятор Java перекомпилили в нативный код через GraalVm что. Все это привело к очень неплохому приросту производительности на ровном месте.
Поэтому я считаю, что пока речь не заходит о чем-то узкоспециальном, типа алготрейдинга, микроконтроллеров, или еще чего-то с четко очерченными не в пользу разработчика рамками, нарисованными окружающим миром в ареале использования, — о производительности языка сильно заботиться не нужно
Большое спасибо. Но я как в том числе пользователь считаю что нужна и что менять каждые n лет железо потому что разработчиков перестала интересовать производительность это дич.
Нужна ли современному языку программирования общего назначения строгая типизация? — Нет.
Видимо именно поэтому тенденция большинства современных динамически типизированных языков это вводить какую-никакую статическую типизацию. Привет JS, Python, PHP. И нет особо тенденции у статических языков от нее избавляется.
Хорошая (для меня) новость заключается в том, что такой язык существует, и я на нём уже десять лет зарабатываю на еду.
Здорово. Но всегда интереснее посмотреть код а не рассказы про него.
Когнитивная нагрузка увеличивается не от свойств языка, а от удачных или неудачных инженерных решений.
Если у вас задача с развесистой предметной областью и миллионами строк кода, вы своими мапами вместо объектов не уменьшите, а бесконечно увеличите когнитивную нагрузку. А если вы в магазин на колене завезли иерархию менеджеров фабрик диспетчеров, то проблема не в языке.
Всё, что востребовано - нужно. Пояснения миллионам программистов самой различной квалификации и различных областей, что им нужно, а что нет, это не инженерный вопрос, а гордыня.
Миллионы мух не могут ошибаться!
Миллион мух, разумеется, имеют гораздо более разнообразный опыт, чем одна муха. Которая, к примеру, пишет, я цитирую:
"мы же как-то обходимся джейсоном для передачи «объектов» туда-сюда? "
Кто мы? Куда передаёт? Как обходимся? Много сотен тысяч из этого миллиона мух (за пределами любезной вашему сердцу предметной области) никогда в жизни не передают никаких объектов в джейсоне. У вас же претензия на некую общность, про "хорошо спроектированные языки общего назначения". Общего, вы компрене? Общего, а не специального языка для перекладывателей джейсонов.
Ну и остальные обобщения выдают приблизительно такой же масштаб кругозора у человека с тридцатилетним стажем в разработке, свободно пишущем на более дюжины языков.
Спасибо, что выдернув кусок из контекста, прямо опровергающего ваше следующее кхм… утверждение — подарили мне возможность просто проигнорировать вас, как тупого дегенерата, не умеющего вести диалог без диффамаций.
Знаете, очень крутой комментарий, им совершенно невозможно оскорбиться! Пытаясь сопоставить слово "диффамация" в вашем исполнении с его словарным значением, я не могу быть уверен, что и, к примеру, выражение "тупой дегенерат" для вас означает то же самое, что и для других носителей русского языка.
Это даже даёт какую-то надежду. Возможно, и прочие слова из вашего опуса также следует понимать в каком-то новом, одному вам ведомом поэтическом смысле. Возможно, под инкапсуляцией вы подразумеваете инсоляцию, а под типизацией пиритизацию. Тогда, конечно, никаких претензий быть не может.
Сколько будет 1+1? Правильно, 100100. Потому что первое число в метрах, второе в километрах, а результат записали в сантиметрах. Это именно то, что решает строгая типизация - не позволяет терять миллионы долларов и человеко-часов только потому, что кто-то там дюймы с миллиметрами попутал. В строгой типизации не получится помножить тракторы на помидоры, даже если в их основе лежат одни и те же примитивные типы.
Вам продали этот маркетинговый булшит, да не просто продали, а еще и сделали его евангелистом, и вы теперь простейшие тезисы не слышите, когда вашу священную корову обижают.
Ваш тезис :
>Строгая типизация без завтипов — детская игрушка.
Ничего не объясняет. Не могли бы вы его раскрыть?
Например в моих проектах строгая типизация очень часто выручает.
Или другой пример, полгода назад переписывал java решение на rust. Так даже не самая лучшая система типов в расте позволила выявить и убрать целый пласт проблем изначальной системы.
Ничего не объясняет. Не могли бы вы его раскрыть?
Людям зачастую жизни не хватает, чтобы его раскрыть. Все удочки я дал, если вам любопытно — копайте. Почитайте, например, про Idris, это неплохой старт.
в моих проектах строгая типизация очень часто выручает
Выручает в каком именно смысле? Ваш редактор подсказал вам, какую переменную использовать? Теги, которые я предложил в тексте, справляются с этим ничуть не хуже.
переписывал java решение на rust
А в изначальной системе была какая-то особая джава без строгой типизации?
Людям зачастую жизни не хватает, чтобы его раскрыть.
Выручает в каком именно смысле? Значит это просто какая-то нишевая дичь, извините.
Выручает в каком именно смысле?
Проще писать код, меньше лишних рантаймовых проверок.
По нашей статистике на раст проекте меньше заводятся дефекты и почти нет реопен дефектов.
А в изначальной системе была какая-то особая джава без строгой типизации?
В джава типизация не расширяема, по сути. Обьекты это заменяют.
По нашей статистике на раст проекте меньше заводятся дефекты и почти нет реопен дефектов.
Дело не в языке, и уж подавно — не в строгой типизации.
Если дело не в языке, то зачем вы так топите за один язык и принижаете другие?
Как может быть дело не в языке если:
Один запрещает прямую работу с памятью, другой позволяет мат операции над указателями
Один разрешает совместную работу с любыми структурами в мультипотоке, другой разрешает только использование thread-safe типов
Один разрешает null значения, другой запрещает
Один разрешает складывать метры с яблоками, другой - нет
От разработчика зависит, конечно, но очень странно слышать, что дело не в языке.
Просто спрошу: это одни и те же люди стали допускать меньше ошибок при переходе с джавы на раст? Это один и тот же проект (порт), или два разных, причем на расте — он в 10 раз меньше и проще?
Команда одна, да. Раст знают еще не очень хорошо, правда.
Это порт, для потребителей сервиса снаружи ничего не меняется.
На расте он по кодовой базе именно стал существенно меньше прям сильно существенно. Не в 10, но раз в 5-6 точно (заинтересовал посчитать точнее).
По потреблению памяти под нагрузкой - разница в 12 раз.
Разница по занятому процессорному времени в 2.5 раза.
Скорость старта с 30 сек, до 300мс.
Поздравляю, значит в вашем случае решение, вроде бы, было верное.
Это всё похвально, однако никак не доказывает утверждение о пользе именно типизации.
Мы вот, например, было дело, сократили один проект в 60 раз, с 15 мегабайт ручного исходного кода на типизированном C++ до 250 килобайт ручного исходного кода на бестиповом Scheme (в обоих случаях этот код разворачивался автоматическими преобразованиями в 18 мегабайт обрабатываемых транслятором операторов). Что это доказывает? Только то, что к разным задачам целесообразнее разные подходы.
Или что писать по второму разу, когда осведомлен обо всех подводных камнях, — проще.
Я думаю про пользу типизации в конкретном примере говорило то, что они нашли целый пласт проблем, которые решили.
Это что за проблема такая, если её не видно до перевода на другой язык?
"Переменная может быть не инициализирована в некоторых ветках выполнения" или "объекты таких подтипов могут не поддерживать операции"
Что нибудь в этом духе
Использование неинициализированной переменной уже вроде просто абсолютно все языки не проигнорируют, а duck typing за то в народе и любят, что нет вот этих палок в колёса, когда я знаю, чего хочу.
Но в том комментарии выше переводили с джавы, она не позволит ни одного из приведенных вами примеров.
Да, про конкретный кейс надо спрашивать, возможно что нибудь с потоками.
По поводу duck typing - собственно это и есть камень преткновения с основной функциональностью типов. Одни хотят быстро и удобно, пишу как хочу, с той стороны подхватим.
Другие не хотят давать писать так как хочешь, а только как запланированно.
Банально использование API библиотек имеет разную выразительность в условном питоне, где свойства предлагается передавать свойствами и флажками и обычными дефолтными C#/Java, где объект просто нельзя сконструировать, не передав ему нужные параметры.
Когда пишешь код, с которым взаимодействуют другие люди, как то не очень продуктивно описание в духе "иди документацию почитай, чтобы понять, как использовать мою функцию" или "лезь в код, чтобы понять, что должно быть в параметре validator и какая у него должна быть сигнатура"
Когда пишешь код, с которым взаимодействуют другие люди, как то не очень продуктивно описание в духе «иди документацию почитай, чтобы понять, как использовать мою функцию» […]
Я мейнтейнер более десятка библиотек, мои коммиты — чуть ли не в сотне других, включая сам язык. И представляете себе, буквально в 100% из них — для того, чтобы понять, как использовать функцию, надо идти читать документацию. И ничё.
Мне никто ничего не продавал. Я пришёл к ООП полностью самостоятельно, ведомый желанием писать сложные и надёжные программы, и даже классический труд от банды 4х до сих пор не прочитал. И уже 2-й раз привёл конкретный пример, которому вам нечего противопоставить, кроме как свести сам факт использования ООП к религии. Но ваша позиция мне понятна - потому что этап неприятия ООП я тоже проходил.
которому вам нечего противопоставить
Есть, прямо в тексте, причем, но вы ничего не слышите и не видите за пределами своего мира.
ваша позиция мне понятна
Нет, не понятна. Была бы понятна — вы бы не твердили как заезженная пластинка на патефоне про дюймы и миллиметры. Это и есть маркетинговый булшит, который невозможно продолжать повторять, если хоть немного обдумать.
Ну и, разумеется, приятие, или неприятие — тут совершенно ни при чем. Я 30 лет назад на дельфях писал, и меня все устраивало.
вы бы не твердили как заезженная пластинка на патефоне про дюймы и миллиметры
Но это же неправда - я привел этот пример ровно один раз. А предыдущий пример был про объём кода в 5 раз меньше для решения одной и той же задачи. В 5 раз меньше - это более чем объективный показатель.
Да, пардон, вы лично этот аргумент использовали впервые. Виноват.
А про какой пример с «в 5 раз меньше кода» идёт речь? Потому что я не поверю никогда, что я не смогу опровергнуть тезис про «в 5 раз меньше кода»?
Ага, спасибо. Будучи совершенным профаном в теме кодеков, все-таки уточню: вы же понимаете, что сравниваете два строго типизированных языка, причем пример на шарпах — сильно кастрировал публичный API оригинала?
Он ничего не кастрировал, это в принципе другой SDK, просто для решения абсолютно тех же задач и с не меньшей функциональностью (и даже большей). Причём если брать реализацию хоста, там разница в количестве строк уже на порядки выходит. Реализация на c++ с теми же идеями у меня тоже есть, развивается параллельно.
Легенды гласят, что раз в пяток лет на Хабр приходит папка, бятя, одним словом пахан от мира программирования и учит сопливых пацанов жизни. Я всячески одобряю, только, пожалуйста, по пятницам, чтобы можно было посмаковать комментарии.
а в итоге получаем софт в котором 1 вкладка хрома есть 200+мб, а ведь когда-то NFS вмещалась на 24 дискетки, а Starcraft BW бегал на 8мб оперативы
Хорошо спроектированный язык в развитии не нуждается.
Ха! Кто-то догадался сказать это вслух. ;-)
Строгая типизация без завтипов — детская игрушка. Но это еще не всё: поспешно втаскивая типизацию в языки, где её доселе не было, и где она — чужеродное тело, — втаскиватели понимали, что просто так аверажный разработчик в этот омут не полезет, поэтому вкатывание упростили при помощи «типа джокера» —
null
/any
/interface{}
.
Было бы крайне удобно читать более развёрнутые рассуждения, чтобы лучше понимать происходящее. Что же имеется в виду?
Завтипы -- зависимые типы, то есть такие, у которых тип результата может зависить от значения аргумента. В качестве простейшего примера можно рассмотреть такую функцию:
function foo(i) {
if (i == 0) {
return 10;
}
return false;
}
Если её типизировать в тайпскрипте получим что-то такое:
function foo(i: number): number | boolean {
if (i == 0) {
return 10;
}
return false;
}
При этом, при попытке использовать foo(0)
нужно будет либо делать дополнительные проверки, либо касты, хотя по коду функции понятно, что foo(0)
это всегда число. Тут-то и приходят на помощь завтипы. В более сильных системах типов можно выразить это ограничение явно:
Definition foo_type: Type :=
forall (i: nat),
match i with
| 0 => nat
| _ => bool
end.
Definition foo: foo_type :=
fun i =>
match i with
| 0 => 10
| _ => false
end.
И при попытке использовать foo 0
как число тайпчекер не вывалится с ошибкой:
(* Работает *)
Definition test1 := (foo 0) + 1.
При этом проверка типов всё ещё есть, и в этом можно убедиться попробовав один вместо нуля:
(*
Падает с ошибкой:
The term "foo 1" has type "bool" while it is expected to have type "nat".
*)
Definition test2 := (foo 1) + 1.
А оно может что-нибудь типа "если аргумент - простое число, то результат строка, иначе - False"?
В результате разработчик оказывается перед выбором: либо аккуратно выписывать все типы до седьмого колена ...
В какой ситуации выписывать? Для чего выписывать?
Как полемический задор, статья хороша. В остальном - нет.
Хорошо спроектированный язык в развитии не нуждается.
Ну, значит, Erlang и Elixir плохо спроектированы. Зачем-то продолжают выпускать новые версии и даже с новыми синтаксическими возможностями...
Нужна ли современному языку программирования общего назначения производительность? — Нет.
Если речь про то, что допустимо падение производительности в, условно, 10 раз по сравнению с идеалом, вылизанным на C и ассемблере с учётом кэширования, цены синхронизации и прочего низкоуровневого стаффа - могу согласиться, чуть со скрипом. Если про падение в 100 или 1000 раз - уже нет. Никто на такое не пойдёт. Надо всё-таки выставлять границы.
Нужна ли современному языку программирования общего назначения строгая типизация? — Нет.
И автор явно перепутал несколько разных осей классификации типизации. Ещё и не смог объяснить хоть сколь-нибудь внятно, что имеет в виду.
Когда в переменной, поле структуры, значение или ключ в мапе, где угодно и как угодно назовите - может быть или число, или строка, или вообще сложная структура - это первая ось. Да, нормально тут говорить про динамическую типизацию, но я подозреваю (из своего уже опыта с Erlang), что это нельзя исключать.
Когда нам надо устанавливать, что вот в этом аргументе функции диапазон значений может быть только от -9000 до +8000 и поэтому мы устанавливаем для него int16_t или int32_t - это вторая ось.
Когда мы говорим о том, что строка, содержащая, например, "00016xp", может быть незаметно для разработчика прочитана как 16, или как 14 (ибо в сишном стиле ведущий ноль это восьмеричное), или 22 (шестнадцатиричное), или вообще дать ошибку, потому что лишние нечисловые символы - это третья ось.
И что именно имелось в виду - ХЗ. И, кстати, Erlang (Elixir, неважно) тут не поможет. Целые у него, например, безразмерные, а вот плавучие - IEEE754, соответственно, точности дальше 15 десятичных знаков не будет.
А если конструктивно - то я согласен, что во многих местах имеет смысл допускать условное any. Например, в сопровождающих данных ошибки. Но не там, где мы уже чётко знаем, что вот тут полагается именно целое неотрицательное, потому что количество обработанных клиентов не может быть равно {ok, mumu}. Не верьте - попробуйте добавить 1 к нему.
Нужны ли современному языку программирования общего назначения классы и их экземпляры? — Нет.
В экземпляре класса нет ничего такого, что нельзя было бы выразить гораздо более внятно, лаконично и прозрачно — обычным словарём.
Про ошибки в именовании ключей словаря (мапы) уже говорили рядом.
Есть инкапсуляция, как защита от ошибок другого типа - как нарушение инварианта. Думать в стиле ООП "рыбы в аквариуме", когда каждый объект это процесс Erlang - удобно, но в итоге это обман, потому что:
В конце концов, мы же как-то обходимся джейсоном для передачи «объектов» туда-сюда?
Нет, бывает, что не обходимся. RPC с объектами, проксями и стабами придумали не просто так.
Самое удивительное, что Гвидо был на полшишечки от этого решения, когда придумывал «специальные методы» в питоне (), но потом неугомонный улучшайзинг всё испортил.
Интересная мысль о том, что же на самом деле думал Гвидо. Самое время вспомнить рассказ Донцовой как она лично у Катаева выясняла, что он думал:)
иначе придётся переусложнять (портить) язык циклами.
И ещё один подводный камень, чтобы ободрать дно. И вся статья в таком духе.
и я на нём уже десять лет зарабатываю на еду.
А кто-то зарабатывает на Коболе. Простите, не аргумент.
PS: На Elixir я не писал. На Erlang - писал, много и серьёзно. Опыт полезный и интересный, но впечатления очень неоднозначные. Как общее средство я бы его не рекомендовал. То, что он при всём шуме в 2000-х не выстрелил, показывает, что у него таки серьёзные проблемы. Часть из них исправлять не собираются, хотя было бы легко - это показывает ограниченность управляющей команды.
Нужно ли «развитие» языкам программирования