Как стать автором
Обновить

Комментарии 337

Легко смотреть в прошлое и ругаться на то какие ошибки кто-то сделал. Не так легко понять, что нужно сделать, чтобы не допустить эти ошибки. На 10 вещей которые вы перечислили было еще 1000 которые не полетели.
«Объективно лучше» не всегда объективно. «Хорошо сейчас» не всегда хорошо через 5 лет.

Я согласен с посылом, что разработчики компиляторов такие же разработчики как и вокруг, но когда все, что вы пилите это протокол взаимодействия (с разработчиками как консюмерами этого протокола) любая фича становится потенциальным костылем. В таких случаях помогает идеология разработки. Она может быть как правильной так и ошибочной, но многим архитекторам она нужна, чтобы как-то ограничивать поток функциональности в условиях огромного кол-ва неизвестностей.
Вобщем, я с вами согласен. Но некоторые примеры настолько очевидны, что уже сложно спорить. Например ближе к концу есть абзацы про Java, C# и enum'ы в Scala. Те, кто спорил потом переобулся без объяснения причин. И говорим мы о прошлом только потому, что ретроспективна очевидна их неправота.
Ну я бы поспорил насчет enum. Тут немного другая ситуация. Это фича, без которой можно вообще прекрасно жить. Я вот без нее много лет живу, и просто не замечаю, что их там где-то нет. И когда они завтра появятся — я не замечу, скорее всего. В моем прикладном коде они нафиг не нужны, а там где я применяю чужие — мне их хватает. А не хватит — я на коленке напишу что-то на базе sealed. И что характерно — будут счастлив.

Ну то есть, вывод что:

>сам факт добавления нового ключевого слова enum прямо говорит о том, что эти костыли не работают как надо

он… ну не то чтоб прямо неверный, а скорее недостаточно доказанный. Есть много других вариантов, которые не рассмотрены.
Погодите, тогда получается еще хуже — в язык совершенно без надобности добавляют новое ключевое слово спустя долгие годы его существования. Т.е. это нормально взять и чего-нибдуь ненужного добавить в язык?
Я был в ситуации где нужны енамы и совместимость с Java и все остальные нормальные характеристики енамов, которых ныне существующие костыли не имеют. Я завидую вам, что вы не бывали.
enum в первую очередь — синтаксический сахар для более лаконичного выражения ATD в scala3/ Цитата из документации:

An enumeration is used to define a type consisting of a set of named values.


enum Color {
  case Red, Green, Blue
}


This defines a new sealed class, Color, with three values, Color.Red, Color.Green, Color.Blue. The color values are members of Colors companion object.


И уже во вторую очередь это те самые любимые enums, которые можно подружить с Java.

То есть мотивация у разработчиков немного другая, хотя на выходе мы получаем фичу которая подходит и для enums и для ADT.
Со всем согласен. Я пытался в очень простую логику. Енамы — это далеко не лябда функции и не какие-нибудь сложные дженерики. Это довольно простая фича языка, которая есть почти везде.
Теперь, если они не нужны — то не понятно, зачем их добавляют (помните у нас ведь есть Enumeration в Scala из коробки...). Если они нужны, то не понятно, почему так поздно и что это за лажа была c Enumeration.
Просто придумали Enumeration, а на практике оказалось что sealed классы решаю проблему лучше в большинстве случаях (хотя немного многословны). А сейчас добавили энумы, которые по-сути являются синтаксическим сахаром для sealed классов + одновременно добавляют поддержку GADT. Вообще, имхо, на скалу грех жаловаться по поводу недостатка чего-то. Она зафарширована фичами по самые уши. Тем более, есть возможность расширять сам язык планигами (особенно в dotty) или написать свой DSL. На самом деле, некоторые фичи в дотти портинованны именно из сторонних плагинов и библиотек. Например, плагин kind projector привнес туда Type Lambdas и Wildcard Arguments in Types. Из Shapeless туда переехал аналог HList-ов в виде продвинутых tuples и Polymorphic function types.

Тут нужно понимать что добавление фичи в язык и добавление фичи в код приводит к разным последствиям. Ваше произведение — это книга, а продукт разработчиков языка — слова и алфавит. В вашей книге важна нить повествования, вы можете прозрачно менять абзацы текста не теряя смысла. А теперь представьте приходят писатели к Кириллу и Мифодию и говорят: "Давайте добавим пару красивых букв из арабского и пучок иероглифов из китайского и майя, эти ребята космопланы строили они фигню не посоветуют". Ну и слов новых из Хинди, а предложения будем строить как мастер Йода, а то на русском мало слов, вот и приходится писать портянку текста чтобы раскрыть свою мысль, да еще и за порядком слов следить.
Изменение языка это в первую очередь обратная совместимость и поддержка, в текущей реализации бесконтрольное добавление функциональности в язык сродни созданию Вавилонской башни. Добавить фичу "могут не только лишь все, мало кто может это делать".

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

Я не раз слышал, как медленное добавление фич в java объясняли именно этим: мы не хотим добавлять что-то, что потом окажется ненужным или плохо спроектированным. Особенно с учетом того, что ничего не выбрасываются [и на свои ошибки мы будем смотреть еще 10 лет, а краснеть за них на конференциях — 15].
По-моему, это довольно весомый аргумент не торопиться — то, в чем вы упрекаете разработчиков java в статье.
Т.е. раньше предпочитали делать мало, но "высекать в камне": раз и навсегда. Сейчас политика изменилась: выпускают чаще, экспериментируют в ветках (как с Graal), которые (через ощутимое время) могут быть добавлены в ядро. И я воспринимаю эту смену подходов как политическое решение, решение на уровне топ-менеджмента, а не на уровне разработчиков языка. Хотя, конечно, я могу ошибаться — в этой теме я профан.

Особенно с учетом того, что ничего не выбрасываются

да? -:) а откуда проблемы вроде stackoverflow.com/questions/46402772/failed-to-install-android-sdk-java-lang-noclassdeffounderror-javax-xml-bind-a берутся если «ничего не выбрасывается»?

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

А мне как пользователю какая разница — часть языка выкинули или часть того что раньше входило в «стандартную библиотеку»? И таких вот фокусов — хватает.

В том, что обратная совместимость — это про код, а не скрипт инициализации и module-path. Код, который написан до выкидывания javax.xml (кстати, заметьте — javax, то есть не стандартная библиотека, стандартная-то в java.*) работает как до, так и после — поменялись флаги компилятора, и class-path нужно теперь заменить на module-path.
А что до "таких фокусов" — я и покруче видел. Когда кое-кто реэкспортировал тот же самый javax.xml из пяти, что ли, jar-ников на одном и том же class-path, да ещё немного разные версии, так что в зависимости от положения звёзд грузились классы разных версий (как этого никто не заметил — атличный вопрос для отдельного расследования). В итоге когда они смигрировали — "внезапно" у них посыпались ошибки о том, что javax.xml.bind экспортируют несколько модулей, включая сам javax.xml (который они по всем правилам добавили в module-path, а как же иначе-то).

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


А потом перешли к полугодичным релизам, и за 3 года (с 2017 по 2020) вышло 6 штук (текущая версия — Java 14). За предыдущие 3 года вышла только Java 8.
И я вижу в этом цену скорости внедрения фич: старый код может не скомпилироваться в новых версиях, но зато они выходят быстрее. Насколько это оправдано — тема для другого холивара :-)

>Я завидую вам, что вы не бывали.
Ну, так я собственно в этом смысле и высказался. Не очень представляю себе ситуацию, когда вот прям без них никуда. На самом деле, если реальный случай можно описать — это было бы значительно интереснее посмотреть именно в коде.
Слушайте, про енамы в Скале тонны материалов написаны с примерами и pros и cons. Вот, например, хороший сборник — все адекватные варианты разобраны. Stack Overflow завален обсуждениями о енамах. Все крутится вокруг фич: Exhaustive pattern matching (это важно для безопасности кода), сериализация/десериализация, и совместимость с Java.
Я не понимаю фразу «прям без них никуда» — я даже с ассемблером могу куда-нибудь дойти.

По-моему все просто: облажались с Enumeration, подождали 14 лет прежде, чем пофиксить, наконец-то фиксят.

Лично вопроc к вам. Я не хочу вас обидеть или что-либо, просто вопрос, как вы думаете: нет ли такого, что вам просто неприятно, что в языке который вам (и мне) нравится что-то очевидно поломанное не фиксили 14 лет и это неприятно осознавать и хочется решить когнитивный диссонанс — самое простое отрицать. Типа, ну не так-то и надо было и тому подобное. Как вы думаете — есть такое у вас?
>Я не понимаю фразу «прям без них никуда» —
Я пишу на скале — но я использую некоторое подмножество языка. Поэтому практически любые фичи языка могут оказаться мне не нужны вообще. Соответственно, в такой ситуации для меня вообще практически не бывает киллер фич. Последняя какая была — это лямбды и стримы, потому что они реально многое поменяли, в том числе в том, как я пишу.

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

>это неприятно осознавать и хочется решить когнитивный диссонанс
Я думаю люди просто разные. Меня это не напрягает. Если бы напрягало — я бы не сидел на проектах, где Java 8 билд 171 еще будет долго. А скала… 2.11.8.

Можно вообще прекрасно жить без кучи всего. Можно прекрасно годами и десятилетиями жить без лямбд и вывода типов auto (разработчики на плюсах до 2011-го года), без constexpr (они же до 2014-го), без концептов и модулей (до 2020-го), без рефлексии (до 2023-го в лучшем случае), и так далее. Но с ними лучше.

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


Лямбды волшебны, но в плюсах, где я могу аргументом передать хоть ссылку на глобальную vtable — не нужны совсем. Они замусоривают язык. Ваша усталость от плюсов связана именно с этим, косвенно: вся эта мишура делает несоизмеримо сложнее поддержку компилятора, и ради этого синтаксического сахара UB теперь прет изо всех щелей.


Попытки влезть на елку и предохранить филе от уколов погубили (губят) уже не один нормальный язык. Я ненавижу Go, но без дженериков он хотя бы хорошо закрывал свою нишу. Потом в Го по хайпу пришли люди чуть посерьезнее гугловских джунов, и началось. В результате язык говном быть не перестал, но теперь еще и порог входа будет как в лиспе.


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


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


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

>и ради этого синтаксического сахара UB теперь прет изо всех щелей.
Что-то не помню других языков, у которых количество UB увеличивается пропорционально количеству сахара.
Нет, ситуация с точностью противоположная.

Именно «академические» языки придерживаются принципа ортогональности: в языке не должно быть дублирующих друг друга конструкций. Посмотрите на языки линейки Oberon (от учебного Oberon-07 до промышленного Component Pascal) — вот это пример академических языков.

Большинство же современных «прикладных» языков создаются для удешевления разработки. Добавление синтаксического сахара позволяет снизить требования к уровню разработчика (и, соответственно, к уровню зарплаты этого разработчика). Написание кода на почти ортогональном маленьком Go требует больших квалификации и времени, чем на раздувшемся от синтаксического сахара и дублирующих конструкций JavaScript. В тех же JavaScript или C++ можно выделить по достаточно небольшому подмножеству, которое будет полноценным языком программирования, способным решать весь круг задач исходного языка; всё прочее добавлено только для упрощения жизни кодеров.
Написание кода на почти ортогональном маленьком Go требует больших квалификации и времени, чем на раздувшемся от синтаксического сахара и дублирующих конструкций JavaScript.

То, что на JS пишут все, кому не лень, не значит, что для нормальной разработки на нём требуется невысокая квалификация. ИМХО, для JS квалификация нужна запредельная, чтобы учесть все нюансы языка и среды исполнения. Например, Google может позволить себе любых по уровню разработчиков, но gmail тормозит, и утечки памяти обычное дело, несмотря на автоматическую сборку мусора.
Да, для высокоэффективного использования JS квалификация необходима. Но как часто бизнесу требуется действительно высококачественный код?

Подавляющее большинство современных задач — шаблонная рутина, выполняемая неучами, дрессированными решать стандартные задачи набором тупо заученных стандартных методов. И «обучить» таких кодеров намного проще на JS, чем на Go.

А пример с Gmail как раз показывает, что глючный сервис экономически выгоднее найма высококлассных разработчиков.
А пример с Gmail как раз показывает, что глючный сервис экономически выгоднее найма высококлассных разработчиков.

У Гугла множество высококлассных разработчиков, но сервис таки глючный.
Глючный он потому, что высококлассные разработчики хотят решать высококлассные задачи, а не фиксить баги и вылизивать сервис по мелочам.
Вот тут habr.com/ru/post/350374 бывший разработчик Google пишет, что поиск ошибок делает работнику только хуже, то есть дело в управлении, я не в разработчиках.
Но как часто бизнесу требуется действительно высококачественный код?

Всегда, если бизнесу нужно стабильное решение на годы.

1С Предприятие — стабильное решение не годы, не отличающееся качеством кода.

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

N.B. Формальная верификация обеспечивает очень высокую надёжность кода (куда более высокую, чем любой набор тестов), но почти нигде не применяется — потому, как очень дорого.

Очень дорого, очень долго и очень мало специалистов.

1С Предприятие — стабильное решение не годы, не отличающееся качеством кода.


Нормальное там качество кода. Для продукта такой сложности количество ошибок в 1С удивительно невелико.

Но большее число ошибок содержит не сама 1С, а большее число ошибок совершают те, кто её обслуживают на местах. К сожалению, они не все достаточно квалифицированы.

Но да, виновата у них всегда 1С.

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

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

Python, PHP, JavaScript — живут себе без статической типизации.
А юнит-тесты в 1С есть. Но не все об этом знают, как мы видим по вашему тексту.

Скажете в них меньше ошибок?


А как они там выглядят?

То есть это какой-то сторонний проект, о котором мало кто слышал, а сама платформа не проектировалась для использования тестов.

То есть это какой-то сторонний проект, о котором мало кто слышал,


Это очень известный продукт.

Если лично вы не слышали — то это ваша проблема как непрофессионала.

сама платформа

Какая разница стоит на продукте шильдик 1С или нет, если он решает свои задачи.

Я не программирую на 1С, если что. Но у меня есть весьма негативный опыт прикручивания E2E тестов к приложениям, построенным на платформах, не ориентированных на это. Я писал об этом тут: https://github.com/nin-jin/HabHub/issues/20

Я не программирую на 1С, если что.


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

Обсуждать качество того, чего никогда и не видели?

Конечно, у 1С, как у любого крупного продукта есть косяки.

Но чтобы их обсуждать — нужно разбираться в теме обсуждения.

Вы вообще представляете себе — какие именно задачи решает типичный программист 1С? Типичная работа — корректировка кода под изменившийся бизнес-процесс.

При такой схеме работы написание юнит-теста, займет сопоставимо времени с собственно модификацией программы.

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

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

P.S.:
Чтобы не считали воинстующим невеждой:

Я организую автоматическое тестирование, когда пишу совсем другие вещи. Например, бэкенд-сервера.

Но если вы просто обслуживаете 1С на предприятии — то пользы от автоматического тестирования просто не поймаете.

Я пару лет работал над самой платформой так-то.

Я пару лет работал над самой платформой так-то.

За 2 года как правило люди проходят путь от начинающего новичка до крепкого джуна. Лучшие через 2 года уже могут считаться начинающим миддлом.

А джун — это не эксперт.
Это тот чел, в косяках которого виноват кто-то другой.

Я бы предположил, что вы особо талантливы и за 2 года стали спецом, но судя по тому что вы не знали, что тесты в 1С есть, то, извините, нет.

Позвольте не поверить вашему неэкспертному мнению.

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

То есть это какой-то сторонний проект, о котором мало кто слышал


И это вы пишете об известнейшем продукте.

Еще раз:
Вы рассуждаете о вещах, в которых некомпетентны.

Я пришёл уже руководителем направления. К счастью, конкретно моё направление BSL почти не касалось. Разве что я лишь немного правил код, который писали разработчики платформы. Ну и пытался продвинуть идеи автотестирования и непрерывного деплоя. Не очень удачно, но я надеюсь рано или поздно и до этого дойдут.


На этом предлагаю закончить измерение наших пиписек.

Я пришёл уже руководителем направления.

И не знали об развитой системе тестов?
Руководители разные бывают…
К счастью, конкретно моё направление BSL почти не касалось. Разве что я лишь немного правил код, который писали разработчики платформы.

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

В 1с, вы и сами знаете, сложилась культура что вендор всегда прав, решения не от вендора и не от аффилированных с ним партнером — зло. Так что слышали то многие, но попытки внедрить у многих проваливались по причине сопротивления руководства «это не от 1с».
Просто не возникает ситуации, где автоматические тесты полезны — когда пишем код, вновь написанное ломает код, и тестами проверяем поломанное.


У вас странное представление о предназначении автотестов… Мне казалось, они нужны, чтобы получить некоторую уверенность, что внесенные изменения не поломали соседнюю функциональность, например.

При такой схеме работы написание юнит-теста, займет сопоставимо времени с собственно модификацией программы.


О ужас, такова жизнь, все небесплатно.
А тут всплывает очередная проблема) В 99% 1сники занимаются не разработкой чего то своего, а мелкими (или относительно мелкими) правками в типовых. А с этими самыми типовыми от 1с и франчей естественно никакие автотесты не поставляются.
сама платформа не проектировалась для использования тестов

Не защиты для, но справедливости ради. Сама платформа проектировалась и создавалась во времена, когда никто не писал тесты. Никто. Не было не только библиотек для создания тестов, не было ни джавы, ни джаваскрипта, ни даже веба.


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


Так что обвинять 1С в отсутствии «нативной поддержки для веба» — примерно то же самое, что обвинить ее в самописном интерфейсе вместо электрона.

Язык программирования D со встроенной поддержкой тестов появился в 2001.


1С: Предприятие 8.0 появился в 2002, а тестов как не было, так за почти 20 лет и не прикрутили.


Веб, ява и яваскрип тогда уже существовали, конечно же.

Язык программирования D со встроенной поддержкой тестов появился в 2001.

1С: Предприятие 8.0 появился в 2002, а тестов как не было, так за почти 20 лет и не прикрутили.


Ну не логично же.

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

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

Вы сейчас демонстрируете пословицу «Задним умом все крепки».

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


Вы, наверно, не в курсе, но восьмёрка — это практически полностью (если не полностью) переписанная платформа.

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


Что там c MS Dynamics? ABAP? SAP?
Python, PHP, JavaScript — живут себе без статической типизации.

А разве хорошо живут? Отсутствие статической типизации было одной из причин по которым я из 1с свалил. Не самой важной, одной из очень многих, но все же. А уж учитывая что динамическая типизация накладывается еще и на отсутствие привычки у коммьюнити и возможности писать нормально юнит тесты — так вообще. В js и прочем типы хоть тестами пытаются заменять.
xUnitFor1C в свое время пробовал, но платформа и язык 1с фигово под это заточены. Приходилось костылять, да и неудобно было в итоге.
Была бы там статическая типизация


О!
Метаданные в 1С?
«Нет, не слышал»?

В отличие от классических языков программирования, которые независимы от БД и прикладных объектов,
программа 1С сильно привязана к структурам данных в БД и к визуальным объектам.


Многие мои знакомые считают, что без ошибок — серьёзных программ не бывает. Случается, программист сам, что делает, не понимает и за бутылкой пива обо всём забывает. Конечно – разбираться потом, ему будет влом.

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

Но всё равно, всё равно не пойму твою прогу, хотя, понемногу, между багов нащупал дорогу, но что ж их так много, ей богу?

Тут такая фигня. Сказал чуваку, что покупать 1с — это модно. Знаешь, что он сделал? Он дал мне в морду!
...

Часто бизнес довольно разумно понимает, что на годы стабильности не будет. Новые рыночные и нерыночные условия, от требований регуляторов до моды, часто ставят бизнес перед выбором: или выкидываем фичу, которую долго пилили, или терям долю рынка. Например, годами могла развиваться архитектура с требованием "ни один байт о действиях пользователя не должен быть потерян", а тут бац и должен быть удалён отовсюду, включая бэкапы по первому чиху или по истечению активности. И записывать должно только то, что нужно.

Но как часто бизнесу требуется действительно высококачественный код?

Если мы говорим про JavaScript на фронте, то почти никогда. Он он очень нужен пользователям приложений, которые наваял этот самый бизнес. А там слёзы одни. У бизнеса всё хорошо, фича закрыта, бабки получены, а у пользователй эта фича ставит на колени Core i7 и требует стабильный канал в 10Мбит, чтобы отобразить пару формочек…
Так и живём.

Да, так и живем. Потому что «действительно высококачественный код» очень редко является существенным конкурентным преимуществом. А вот скорость выхода на рынок с новой возможнотстью — является.И, тем более, производительный и эффективный код тоже редко является конкурентным преимуществом: массовое оборудование сейчас стало настолько производительно и дешево, что затраты денег и задержки по времени на написание эффективного кода не окупаются.
Если было бы иначе, то бизнес был бы озабочен качеством и производительностью кода, потому что это напрямую бы влияло на прибыль. А так — имеем, что имеем.
С моей точки зрения, именно тут кроется основное отличие академического языка от прикладного. В академический язык можно и нужно добавлять все пропозалы и разрешать все экстеншены: поиграться, посмотреть, надо ли. Прикладной язык должен оставаться максимально простым.

Ну вот в Rust есть деление на стабильную версию и нестабильную (nightly). Все новые фичи попадают в первую очередь в нестабильную версию, где их можно применить на практике и посмотреть, как они работают, а в стабильную добавляют только после того, как доведут до приемлемого состояния. Очень помогает от ситуаций вида "ой, мы добавили новую клёвую фичу, но на практике у неё оказались недостатки, но избавиться от неё мы теперь не можем, потому что это нарушит обратную совместимость".


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

Простота языка и простота оптимизации связаны примерно никак.


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

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


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

Технически ассемблера достаточно для написания любого софта, но почему-то на практике используют что-то более фичастое. Конкретно касательно лямбд — да, на C++ вполне можно сделать свой тип с operator() и это будет типо лямбда, но для этого придётся полностью расписать все переменные, которые она захватывает (а их может быть довольно много) и потом ещё их все корректно инициализировать, ибо что-то захватывается по ссылке, что-то по значению. Да, так можно делать — но никто так на практике делать не будет, потому что это бойлерплейт, причём ещё и не переиспользуемый, если функция используется единожды. Ах да, этой псевдо-лямбде нужно будет ещё и имя — а вы ведь помните, какие две самые трудные проблемы в программировании.


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

Во-первых, C++ никогда и не был про безопасность (хорошо это или плохо — вопрос отдельный (правда, лично я считаю, что плохо)), во-вторых, со своими бойлерплейтными лямбдами шанс сделать какую-то ошибку скорее увеличивается, просто потому, что это тупо больше кода. И, кстати, не могли бы вы привести пример новых UB, связанных именно с лямбдами?


Попытки влезть на елку и предохранить филе от уколов погубили (губят) уже не один нормальный язык. Я ненавижу Go, но без дженериков он хотя бы хорошо закрывал свою нишу. Потом в Го по хайпу пришли люди чуть посерьезнее гугловских джунов, и началось. В результате язык говном быть не перестал, но теперь еще и порог входа будет как в лиспе.

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


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

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


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

Кто будет определять, когда имеет смысл использовать трансформации AST, а когда достаточно более приземлённых средств языка? Кому "можно доверять"?

И, кстати, не могли бы вы привести пример новых UB, связанных именно с лямбдами?

Стало легче сделать что-то вроде


auto make_fun(int arg)
{
  return [&] { return arg; };
}

Впрочем, не то, чтобы это было новым UB.


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

и ради этого синтаксического сахара UB теперь прет изо всех щелей.

UB в C/C++ нужен для того, чтобы позволить языку эффективно компилироваться на самых разнородных платформах. С количеством синтаксического сахара это никак не связано.


скажем порядок вычисления аргументов в
x=foo( bar(1), bar(2), bar(3) );
не задан вовсе не потому, что "не смогли".

UB в C/C++ нужен для того, чтобы позволить языку эффективно компилироваться на самых разнородных платформах. С количеством синтаксического сахара это никак не связано.

Эффективная компиляция вполне возможна и без UB (теоретически, по крайней мере, но на практике-то и плюсы никто не знает, так что от теоретизирования мы ничего не теряем). Просто нет выразительных средств у языка для того, чтобы таскать доказательство, что ptr /= nullptr, скажем.


скажем порядок вычисления аргументов в [… ] не задан вовсе не потому, что "не смогли".

Во-первых, в C++20 таки стал задан, а, во-вторых, это никогда не было undefined behaviour. А с первым вполне можно жить.

Не соглашусь.


Проблема, на мой взгляд, с добавлением новых экстеншонов скорее не в том, что язык становится слишком сложным, а в том, что сложно поддерживать все эти экстеншоны консистентными. А конкретно в случае плюсов проблема ещё и в том, что он изначально строился как язык, совместимый с другим языком, со своей историей и созданным в то время, когда о консистентности ещё особо никто не думал. При этом фичи-то на самом деле в плюсах нужные — лямбды всякие эти, концепты, move semantics, прочая подобная ерунда. Это действительно повышает выразительность языка, и в 2020-м году я могу делать то, что в 2014-м (и, тем более, в 2010-м) не мог без какой-нибудь кодогенерации.


Ну и переходить в разработке на более простые языки (go? python?) мне не хотелось вообще никогда.


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

сложно поддерживать все эти экстеншоны консистентными

Ну я это примерно и имел в виду.


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

Не делает. Но переусложняет все экпоненциально.


переходить в разработке на более простые языки (go? python?) мне не хотелось вообще никогда.

Ну это-то понятно, никому не охота. Но я, скорее, имел в виду Julia, Rust, даже Clojure — они выгдядят гораздо консистентнее, на мой вкус.

Ну я это примерно и имел в виду.

Но ведь консистентность бывает разная. Бывает как в плюсах, а бывает, что QuantifiedConstraints не работают с каким-то крайним случаем в GADTs, и компилятор при этом отваливается с ошибкой, а не всё разваливается в рантайме. Ну, печально, но щито поделать.


Ну это-то понятно, никому не охота.

Отзывы вида «раньше я был C++/Java/C#-программистом, а теперь перешёл на Go и мои волосы стали мягкими и шелковистыми» я видел довольно часто.


Но я, скорее, имел в виду Julia, Rust, даже Clojure — они выгдядят гораздо консистентнее, на мой вкус.

Для Rust это временно — дайте ему ещё лет 10. Имхо любой язык, которым пользуются, через десяток-другой лет становится немножко монстром. А джулия там или clojure — ну, я тоже не вижу каких-то личных стимулов на них писать. Мне вот потребовалось поковырять совсем чуть-чуть схемку (в неё idris 2 компилируется по умолчанию), и для знакомства с лиспами мне этого хватит на годы вперёд.

А кто с этим спорил? Я же о другом вообще. Ну вот тут высказались, что с модулями в Java 9 тоже лучше. И что? Если у вас энтерпрайз, который живет 24*7, и написан 10 лет назад — у него вообще другие потребности, нежели у стартапа. Это так было, и скорее всего еще долго так будет. И тут риски миграции практически перевешивают любые плюсы — особенно плюсы от нового синтаксического сахара.
1. Разработчики языков тоже люди.
2. Разработка языка (как и любой крупный проект, в который вовлечено много народа) — это всегда не только разработка, но еще и немного политика.

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

Диктатура разработчиков языка (меритократия) — худшая из форм управления разработкой языка, если не считать все остальные из уже опробованных.
Я вряд ли открою новость но добро пожаловать в C++ )) У нас есть комитеты и открытые обсуждения, любой может предложить своё улучшение языка и если оно объективно будет хорошим оно попадёт в стандарт, даже есть группа от России которая поможет с продвижением. Нет ни какой зависимости от «единственного» разработчика компилятора )

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

По заголовку и картинке сразу подумал про fillpackart, однако оказался другой автор.
Однако стоило заглянуть в профиль, увидеть 1 публикацию и то, что юзер приглашен fillpackart, все стало на свое место

А ещё ссылка на подкаст, ага. И даже чатик в телеге https://t.me/myobrecheny. Ух

НЛО прилетело и опубликовало эту надпись здесь
>не боги языки програмирования создают.
Э… ну если автор скажем создал десяток языков — то да, эта фраза имеет смысл. А если не создал — то видимо не смог? Либо просто не умеет, либо не смог себя мотивировать, нишу там не нашел подходящую для своего языка. Но вообще говоря, это уже все отмазки.
НЛО прилетело и опубликовало эту надпись здесь
Ну и? Я думаю таки различие между теми кто создал, и кто не создал, имеет место. Потому что рассуждать о вкусе омлета вы несомненно можете, а вот снести яйцо — сильно вряд ли.

Ну то есть, конструктива-то нет. Банальное брюзжание — есть, а как нужно делать — автор нифига ведь не знает. Он бы конечно добавил бы record в C# 9 лет назад, уж непременно бы. Только ктож его возьмет в команду разработки C#?
НЛО прилетело и опубликовало эту надпись здесь
>Если предположить что Microsoft имеет стратегическое направление движения, то наверное могли и пораньше.
Ну, задним умом все крепки. Этот вопрос 10 лет назад легко мог выглядеть совершенно иначе. Ну скажем, с той стороны что мне ближе — возьмем Java, и скажем 2010 год. У меня лично тогда и сегодня — совершенно разные потребности. Если тогда я с энтузиазмом встречал Java EE 6, например, то сегодня мне вообще нет до Java EE дела. При том что Java это все еще мой инструмент. Предсказывать задним числом легко, ты спрогнозируй что будет завтра, и не ошибись — вот это будет достижение.

>Что теперь прикажете делать?
Не, а я что, могу кому-то запретить писать? Даже если мне не нравится этот пост (а он по сути — переписанный помягче первый, который заминусовали нафиг, и прогресс очевидно налицо) — ну так была куча постов еще сильно хуже, с какой стороны на них ни посмотри.
Предсказываю передним числом: Java нужна null-safety и тому есть множество причин и сигналов. Null-safety с болью тащат в C# (тоже толго, особенно учитывая когда появился Nullable тип). Однако по ряду причин, описанных в статье в Java не будет null-safety в ближайшие 5 лет.
>Java нужна null-safety
На мой взгляд — нет. Это чуть ли не меньшая из проблем, которые есть на сегодня. Если у вас в коде есть null — это самое простое, что у вас может случиться. Возможно такие баги легко допускаются — но они также легко чинятся.

Более того, Java 8 это 2014 год, то есть 6 лет назад. И на сегодня на ней все еще живут очень многие проекты. Я думаю еще лет 5 могут прожить, потому что на сегодня (ну я видел отчет на март) это все еще больше половины, и больше чем живут на Java 11. То есть, не будет ничего из перечисленного потому, что новые версии просто никто не использует (я конечно преувеличиваю, но не сильно).

>есть множество причин и сигналов
И столь же много причин ответить нет. Нет, не потому, что не нужна. Не помешала бы. Но угадать правильный выбор между этой и десятком других фич — практически очень сложно. Простой пример — разработчики вложили кучу усилий в Java 9 и модули. И мы видим то, что мы видим — Java 8 все еще везде и всюду, а модули многим проектам просто ничего не дают.
Я ваше мнение уважаю.
Напрягает, что всякими подобными аргументами мне объясняли отсутствие «синтаксического сахара» в Java, в то время как C# уходил далеко вперед. Теперь вы говорите, что люди не пересаживаются на новые версии Java — с чего бы это?
Вобщем, наш разговор через 5 лет: в Java в очередной раз пытаются догоняя добавить все недостающее, но это не особо и надо, потому что те кому было надо сегодня: поменял стек/пересел на Kotlin/пересел на Scala. И мы опять говорим, что проблема не в языке, а в том, что последние версии Java не так бодро адаптируются.
Как вам такая мысль?

Кто объяснял? Разработчики Java? Или мимокрокодилы из интернетов?

Все Java-разработчики которых я знаю. Да и в интернетах полно такого было и есть.

И при чём тут авторы языка? Попробуйте спросить у мейнтейнера — он вам объяснит все трейдоффы. Они зачастую не видны, пока сам не мейнтейнишь.

А Гослинг был главным консерватором в Джаве — тоже известный факт.
Прочитайте статью — там многое написано, про их объяснения в том числе. Почему другие языки смогли а вот в Джава ну вот никак нельзя. Ну точнее можно, но только спустя лет 10.
НЛО прилетело и опубликовало эту надпись здесь
>Как вам такая мысль?
Честно говоря, я вижу где-то тут комментарий, что синтаксический сахар это 10%. Я бы сказал не так — вообще инструмент это 10%. Остальные 90% это в первую очередь чья-то квалификация, высокая или низкая. И как достаточно широко известно — она сильно разная. Потому люди вообще могут адаптироваться сильно разными способами. Кому-то надо фичи, а кто-то пересел на скалу (на самом деле, когда мне хочется чего-то большого и красивого, как слон, я уже много лет беру груви ;).

А с версиями — тут скорее разница в проектах. Совсем просто — у нас скажем хадуп. 2.6, и не колышет, потому что пром, потому что петабайты данных, потому что фигу его так просто смигрируешь на много версий вперед, где есть нормальная поддержка Java 11. Поэтому хадуп 3 скажем будет на новом железе, с самого начала, а старое вообще никогда возможно не смигрирует. Подозреваю, что похожая картинка в мобильной разработке, где андроидная Java тоже слегка не быстро обновляется.
>люди не пересаживаются на новые версии Java — с чего бы это?
На старой версии создано много приложений, которые сейчас работают и надо поддерживать. Перенос на новую версию java требует много времени. Недостаточно скомпилировать приложения на на новой версии, нужно обновить(иногда развернуть параллельно) инфраструктуру где работают эти приложения.
И бизнесу это не интересно. Задачи можно решать и без нововведений.
Так что да, дело не в языке. Не думаю, что кто то из разработчиков принципиально откажется от новой версии java. Но отсутствие каких то новых фич в языке не ограничивает.
>На мой взгляд — нет.
>Нет, не потому, что не нужна.
Железная аргументация, конечно. Но факты показывают обратное — всякие ламбоки котлины и прочее не на ровном месте появились. Эти фичи давно себя показали с положительной стороны, и тут не надо угадывать. Null-safety в Java нужна, очень нужна. Даже необходима.
Многие говорят: но ведь люди живут же как-то? Как-то живут, но тут надо понимать что Java сообщество это множество инженеров старой закалки. И для них писать код — это тяжелая работа, и она должна оставаться тяжелой. Для них нормально писать по 2 дня то, что коллеги на пыхе делают за 2 часа. То, что в других языках автоматизируют — в java предпочитают натренировывать. Язык не позволяет автоматизировать бойлерплейт? Хорошо, мы просто будем везде его писать. А потом заставим IDE его генерировать. И это растёт как снежный ком.
А те части, которые всё таки можно хоть как-то автоматизировать — делают через рефлексию. В итоге получаются простыни хрупкого кода, который сыпется при рефакторинге.
в Java 9 и модули. И мы видим то, что мы видим — Java 8 все еще везде и всюду, а модули многим проектам просто ничего не дают.
В нашем проекте модули прям нужны, но мы не можем использовать Java 9 по техническим причинам.
>Эти фичи давно себя показали с положительной стороны, и тут не надо угадывать. Null-safety в Java нужна, очень нужна.
Так именно поэтому как раз и нет. Что есть ломбоки, котлины и другие средства борьбы с этим явлением. Не языкового уровня.

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

>В нашем проекте модули прям нужны, но мы не можем использовать Java 9 по техническим причинам.
Ну вот видите как замечательно. А нам не нужны — но мы не можем использовать Java 9 по техническим причинам тоже. То есть, для нас они что есть, что их нет — ничего не меняется вообще. Может оракл внедрить Null-safety в Java 8? Очевидно нет. Поэтому мы (коих полно) и используем другие способы.
Так именно поэтому как раз и нет. Что есть ломбоки, котлины и другие средства борьбы с этим явлением. Не языкового уровня.

Вообще-то Kotlin — это отдельный язык программирования.

ну да, не очень понятно получилось с котлином. Имелось в виду то, что изменения, которые принесли бы в Java null-safety, вовсе не обязательно должны быть сделаны в языке. Есть и другие способы для этого, в том числе неязыковые.
Так именно поэтому как раз и нет. Что есть ломбоки, котлины и другие средства борьбы с этим явлением. Не языкового уровня.
Ну, котлин это как раз языковой уровень. А ломбоки не все себе могут позволить(мы не можем, опять же — по техническим причинам). К тому же я сильно сомневаюсь что в оракл сидят и думают «ну есть же ломбок — пускай все им пользуются».
Ну я бы не так сказал. Я бы сказал, что это множество инженеров разной квалификации. То есть я высказываю свое мнение, что мне эта фича не нужна — потому что я решаю эти проблемы много лет, успешно, и другими способами.
Квалификация везде разная, я говорю об обобщенной картине в enterprise разработке. И, к сожалению, она показывает, что многие разработчики с трудом воспринимают что-то новое. Тот же ломбок многие не любят (деды NPE ловили и нам велели).
Ну вот видите как замечательно. А нам не нужны — но мы не можем использовать Java 9 по техническим причинам тоже. То есть, для нас они что есть, что их нет — ничего не меняется вообще.
Есть мнение, что все эти технические причины как-раз и вызваны застоем в развитии платформы и языка. Т.е. многие разработчики просто завязались на восьмой версии(в нашем случае разработчики обфускатора).
Может оракл внедрить Null-safety в Java 8? Очевидно нет. Поэтому мы (коих полно) и используем другие способы.
Кому очевидно? Мне — нет.
Да, вы правы насчет котлина, мне уже намекнули, что я зря его сюда смешал. Речь скорее о том, что неязыковые средства есть тоже.

> в оракл сидят и думают «ну есть же ломбок — пускай все им пользуются».
Я таки думаю, что нет. Но скорее сидят и думают — а какие именно фичи нам сделать в следующем релизе? И вот тут уже выбор становится не таким очевидным.

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

>Кому очевидно? Мне — нет.
Невозможность внедрить в Java 8 что-либо? Да ладно.

End of Public Updates of Java SE 8
Java SE 8 has gone through the End of Public Updates process for legacy releases.

Вы серьезно считаете, что в такие релизы могут внедрять фичи? А это когда-то было? Спасибо если дыры безопасности будут затыкать.
Я таки думаю, что нет. Но скорее сидят и думают — а какие именно фичи нам сделать в следующем релизе? И вот тут уже выбор становится не таким очевидным.
Думаю тут проблема скорее в сложности фичи относительно других. А так — вещь вполне себе важная, в новую Java даже улучшенные сообщения об NPE завезли.
Модули в Java 9 сломали очень много всего, поэтому в частности хадуп до сих пор не может очухаться от этого изменения
Да, тут согласен. Модули важная причина, осложняющая переход.
Невозможность внедрить в Java 8 что-либо? Да ладно.
Не так прочитал, извиняюсь. Думал речь о Java вообще. Насчёт Java 8 Вы правы.

С другой стороны почему вообще выпуски языка привязаны к платформе? Почему бы не сделать как в котлине — отдельно язык, отдельно платформа? Но это уже к ораклу вопросы.
>Думаю тут проблема скорее в сложности фичи относительно других.
Ну да. Но и самой по себе конечно. Ну вот вы как себе представляете null-safety в языке, так чтобы не пересобирать ничего? Кроме своего кода, может быть. Вот вы вызвали чей-то метод, и он вернул null. Чей-то метод написан на Java 6, и скомпилирован Java 8, например. И что будет?
Ну вот вы как себе представляете null-safety в языке, так чтобы не пересобирать ничего? Кроме своего кода, может быть. Вот вы вызвали чей-то метод, и он вернул null. Чей-то метод написан на Java 6, и скомпилирован Java 8, например. И что будет?
Тут надо подумать. Можно сделать опционально включение null-safe по умолчанию для проекта, модуля, пакета или классов. Или отдельно обозначать параметры как null-safe.
Конечно, это не простое дело, я не спорю. Но в тот же C#, например, завезли(насколько я знаю), можно у них подсмотреть.

Но я согласен, что даже при большом желании завтра null-safe в Java не появится. На его внедрение потребуется очень много времени, и проекты будут переезжать очень долго.
null-safety нужен.
Легко чинятся только отлавливаемые сразу баги.
Что важнее, проверка на null на этапе компиляции и до неё — это исключительно синтаксически реализуемая вещь. Нет хорошей возможности реализовать это снаружи, как те же модули.
В любом крупном проекте где важна производительность( и как следствие нет проверок на null хотя бы на загруженных участках), такие ошибки не чинятся просто. В таких случаях всегда допущена какая-то архитектурная ошибка, что приводит к перекраиванию части проекта, т.к. добавлять в горячую функцию проверку — сильно понижать производительность.
Но это всё же проще, чем найти плавающую ошибку с null, ведь она не редко проходит тесты.

В C# есть RegExp. На 4 из 5 проектов он не используется. Говорит ли это о том, что он не нужен?
Какой смысл говорить о статистике версий, если говорить нужно о причинах? А они могут даже не зависеть от авторов проектов. Опять таки, к чему вообще учитывать без 5 минут мамонтов? У них уже есть версия-судьба и они не перейдут ни на какую другую.
>Какой смысл говорить о статистике версий, если говорить нужно о причинах?
Очень простой смысл. null-safety нужен? Ок, в какой версии он будет? Скажем, в 18? Ну так я вам показал, что во многих проектах все еще сидят на Java 8, уже 6 лет. Я вполне понимаю, что у вас в проекте будет самая новая версия. Но и ваш пример, и мой — не более чем статистика версий.

Я когда говорю не нужен — имею в виду именно это. Что это не 100% киллер фича, ради которой все бросят вдруг Java 8 и дружно перейдут на Java xxx. Вот этого скорее всего не будет. Не тот масштаб. Кому это на самом деле нужно — уже пробуют скажем котлин. Или пытаются не допустить архитектурных ошибок, о которых вы пишете.
Что важнее, проверка на null на этапе компиляции и до неё — это исключительно синтаксически реализуемая вещь.

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

Дополню примером.
Вот есть Ceylon — на JVM, и всё там NotNull по умолчанию — а Null это такой специальный тип.
В Ceylon Nullable-типы это синтаксический сахар над типом Type|Null (да, это union), выглядит как Type?, и в каждом месте где такое значение именно используется, а не передаётся дальше — значение нужно явно распаковать, и дальше уже работать с ним как с типичным NotNull чем-нибудь. Мне вообще как идея очень нравится — но это в языке с самого начала дизайн такой. А в Java всё по умолчанию наоборот, Nullable. И при добавлении null-safety обязательно нужно сохранить смысл всех предыдущих программ как есть, иначе энтерпрайз не поймёт такого финта, и никогда не будет апгрейдиться на версию с фичей null-safety.


А раз так, то делать красиво, как в Ceylon, уже не получится, придётся заставлять всех писать много дополнительного кода для определения типов, которые гарантированно NotNull. Ну и так как никто новую плюшку по умолчанию не получит, а чтобы ей пользоваться нужно читаемость кода уродовать (как там, Optional<Type>, да? или @NotNull Type) — уже начинаешь сочувствовать разработчикам Java, ведь им проще всем просто порекомендовать перейти на Ceylon, чем сделать красиво в Java.

Действительно, чтобы рассуждать о вкусе омлета, нести яца необязательно, нужно просто иметь опыт поедания омлета.
Однако чтобы рассуждать о приготовлении омлета, недостаточно быть даже очень квалифицированным едоком.
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь
Фишка сарказма в том, что без контекста он превращается в противоположную по смыслу вещь. Вот буквально, всё что нужно — это забыть (или не вспомнить, или просто не так воспринять) о том, что это сарказм. И вот у вас уже поворот на 180 градусов.
Уже несколько статей было от разных авторов. Не то чтобы это что-то плохое, если рецепт работает, пуркуа-бы-не-па.
Честно говоря, это печалит. Одного fillpackart Хабру за глаза хватает для провокативных флеймовых топиков. Признаться, его одного уже многовато (частые самоповторы, блогерская эмоциональность в ущерб смысловой составляющей и проч.).
(о, моментально ровно два минуса в карму прилетело – видимо, от автора поста и его наставника :-)

Ну, что ж, этот твит довольно ярко показывает что fillpackart заигрался и окуклился в рамках своей псевдопровокативной вселенной.
P.S. Фил, научитесь воспринимать чужие мнения спокойнее, без юношеского максимализма.
(неужели плюсики в карму так деформируют восприятие?)

Так и в прошлый раз было точно такое же ощущение.
Раньше в книгах и статьях по джаве писали, какая это классная вещь — интерфейсы. Как нам не нужно множественное наследование, как с помощью чистых контрактов можно строить расширяемые программы.
А потом вышла джава 8. И те же люди мгновенно переобулись. Теперь здорово иметь в интерфейсах не только сам контракт, но и детали реализации.
Но я чувствую себя обманутым.
Во-первых множественного наследования так и нету, реализация в интерфейсе в том виде в котором она есть не имеет проблем из-за которых отказаласиь от множественного наследования.
И те же люди мгновенно переобулись. Теперь здорово иметь в интерфейсах не только сам контракт, но и детали реализации.


Это все так же считается плохо, эта фича в первую очередь нужна была разработчикам языка чтобы при объявлении инетрфейса не нужно было менять 100500 реализаций. Была проблема что иначе если расширяешь стандартные интерфейсы все бибилотеки которые его наследуют сломались бы. А в джаве так нельзя-обратная совемстимость наше все!
Фича может быть полезна разработчикам бибилотек(спринга, джажкарты), но прикладным разработчикам в большинстве случаев это ненужно.
Теперь здорово иметь в интерфейсах не только сам контракт, но и детали реализации.

Да ну нет же. Это не детали реализации. Эти фичи позволяют делать что-то вроде util/helper методов. Вы объявили в интерфейсе какой нибудь метод sendMessage(msg: String) и дальше делаете методы для удобства sendAllMessages, formatAndSend, sendAsJson… Таким образом вам нужно всего одну функцию переопределить, а бонусом получать богатый API. Раньше это делалось через декоратор/композицию.

Вот чтобы добавить новый метод к интерфейсу, который принадлежи не вам, все равно придется делать по старинке, через декоратор ну или просто helper методы. Что не очень удобно и поэтому в скале есть type classes, а в Kotlin extension функции. Хотя вот это как раз на мой взгляд спорная штука — с ней нужно аккуратно.
С радостью плюсанул бы, если бы была такая возможность.
Ждём от автора в ближайшем будущем новый язык, в котором все будет)
А потом длинную идеологическую телегу, про то почему этого «всего» нет))
Лично я в какой-то момент перестал обращать на это внимание, нет этого — есть что-то похожее, напрягает лишь то, что эти различия обращают твое внимание на индивидуальность языка. Может суть в этом?
Ждём от автора в ближайшем будущем новый язык, в котором все будет)

Боюсь, не дождемся. Есть писатели, есть критики. Критиковать обычно проще.
Вообще это вопрос жизни — нужно ли делать все самому, что получилось отлично или хотя бы хорошо? Я пока не нашел на него универсальный ответ.
Скажу так: если вы ожидаете, что другие люди будут делать в точности то, что нужно вам, то такого вы (и никто другой) не дождётесь и лучше сделать самому.

А вот когда окажется, что сделать самому то, что нужно, тоже не очень получается, то через принятие приходишь к тому, что то, что предлагают другие, довольно ценно.
Это интересная мысль. Думаю да — если везде был хотя бы базовый набор, я бы даже не замечали что переключаюсь между языками. Ну за исключением переключения ООП-ФП-Нативщина…

А что входит в этот базовый набор? Мне вот без завтипов стало тяжко.

А так вот трудно прямо список дать. И мне, кажется, он во времени меняется.
Зависимые типы для меня пока еще не в наборе, но уже вот-вот будет там. Отчасти такие фичи начинают восприниматься как необходимые, после того как в одном языке сделают и всем понравится и потом через 2-3 года уже везде хотят. Раньше этот процесс был медленнее — потому что разрабы были как фанатики, выучат что-то одно и сидят нахваливают. Не было перетекания знаний и идей в обществе. Сейчас с этим лучше и будет еще лучше по мере того, как люди осваивают разные стэки.
а мне всегда было интересно, откуда только берут люди все эти хотелки, ну реально — кастомные примитивы, что они дадут полезного?
>а мне всегда было интересно, откуда только берут люди все эти хотелки

― Отчего же на закате, Степан Степанович?
― От глупых сомнений, Фимка. Вот глядит человек на солнышко и думает: взойдёт оно завтра аль не взойдёт?


Вот там эти хотелки и берут.
Если конкретно про кастомные примитивы, то:
Лично я почувствовал боль, когда пересел с C# на Java (в 2013 году) и обнаружил, что DateTime в Java — это reference type. В .Net всегда были кастомные и ими пользовались по делу, например для DateTime и Guid.
Вцелом, если не нужны кастомные, то может быть и некастомные не нужны тоже? Зачем какие-то исключения вообще — здесь у нас reference, а тут у нас primitive. Это заставляет разраба думать об этом, у этого должен быть какой-то профит…
В финансах (критичных к внезапной сборке мусора) очень важно не создавать мусора, из-за этого там DateTime — это всегда long unix-time только в UTC. И куча helper-функций чтобы ч ним нормально работать… С кастомным примитивом DateTime этот огород был бы не нужен.
а причем тут примитивы, это вы походу имеете в виду типы значения? Примитивный тип это сахар типа int, который на самом деле тип значение Int32 в C#. Я же говорю чем сахар конкретно поможет. Тогда называйте это своим именем чтоли.

Нет, просто в java в принципе нету value types, а в C# они есть, а примитивы есть и в C# и в Java.
Пишите на C++ или на другом языке без GC и возможностью передавать любой тип по значению и по ссылке. Ну и при чем здесь «примитивы» неясно.
Java Primitive Types же? Что не так? Примитивы = Примитивные типы = Primitive types…
Не обязательно писать на C++, можно иметь GC и при этом иметь кастомные примитивные типы.
Java Primitive Types же? Что не так?

Специально проверил, что в Java называют примитивами, и (как я и думал) то же, что и в других языках (т.е. int/bool/char итп). Буквально в вашей же ссылке выше об этом написано. value-типы — это другое, и опять же они так называются везде.
Но вообще суть не в терминологии, а в выборе инструментов под задачу.
Типы int/bool/char в .Net как раз и есть «Built-in Value Types» (внимание на «Value») docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types#built-in-value-types.
Но мы далеко ушли от темы, с языком в котором целая индустрия использует long вместо DateTime что-то явно не так — все, что я хотел сказать.
Внимание на «built-in» и «simple» :) Используйте классы, кто ж вам мешает. То, что вы пользуетесь костылями говорит скорее либо о преждевременной оптимизации, либо о неправильном инструменте (зачем использовать язык с GC, если вам так критично время?)
Ну правильно — есть Value Types — built-in и custom.
В Java только Primitive Types — все никак ничего custom не определить.

Почему-то в C# DateTime и Guid по значению — это не преждевременная оптимизация, а в Java — преждевременная.
Не пора ли и вам переобуться сударь?

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

А что делать если я программирую на Си?

Плакать.
НЛО прилетело и опубликовало эту надпись здесь

О да, C11 — это всё ещё возмутительно новая вещь, не проверенная временем. /s

А C2x можно сразу предать анафеме.

Радоваться, что Вы не напишете статей подобных данной! :)

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

Я могу обнять вас крепко

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

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

С возрастом вы еще вернетесь к этому состоянию.

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


Надоело, что индустрия зависит от прихоти создателей языков программирования? Ну так это нормально. Не нравится — запили свой Один Самый Правильный Язык для Всего с генериком и лямбдами. И будешь зависеть только от самого себя.

Как программист, я не могу сказать: "да, пользователи хотят эту фичу, но лично мне она не нравится — поэтому ее не будет"

А вот как Product Owner именно это и можно сделать. И зачастую даже нужно. Скажем в геймдеве потакание хотелкам сообщества может сильно навредить.


Вообще не стоит забывать, что довольные люди на форумах не пишут. На один процент недовольных, которые хотят какую-то фичу приходится 99%, которых все утраивает.

>потакание хотелкам сообщества может сильно навредить.
Вы еще не забывайте, что любой выбор за тут или иную фичу — это всегда выбор против другой фичи — на которую не хватит ресурсов. Поэтому все эти заявления, что в язык не добавляли то-то и то-то много лет — они не имеют смысла вообще без перечисления того, что туда добавляли. То есть, на что уходили ресурсы команды разработки, сколько в ней было людей, что они все это время делали.
Я сейчас скажу страшную и крайне неприятную для всех разработчиков ЯП вещь: синтаксический сахар крайне слабо влияет на продуктивность. Вы не получите двухкратный рост продуктивности, перейдя к примеру с C++11 на C++20 или с Java на Kotlin. В лучшем случае там будут считанные проценты. А то ведь бывает и так, что продуктивность наоборот проседает, когда новые фичи приносят с собою кучу новых UB и разнообразных граблей.
Сильнее всего на продуктивность и удобство работы с языком влияет всего три вещи, на которые разработчикам как раз и хорошо бы обращать самое пристальное внимание: библиотеки, документация, IDE.
Когда вы желаете, скажем, разработать игру, и вдруг выясняете, что весь низкоуровневый код для работы с сетью, графикой, звуком и даже текстовыми строками вам придётся написать самим — то плевать, что у языка супер-пупер красивый синтаксис. Используя такой язык, вы будете тупо и бессмысленно терять время на велосипедостроении.
Поэтому я бы предпочёл, чтобы разработчики вместо 10 синтаксических фич добавили ещё 10 классов в стандартную библиотеку. А не как в каком-нибудь C++, где до 2030 года в стандарте совершенно точно не появится даже работы с сетевыми сокетами…
И лёгкость подключения библиотек тоже рулит. Если проще написать библиотеку заново, чем заставить собраться и подключиться уже готовую, то такой язык будет весьма слабопродуктивен. Поэтому если вы делаете новый язык, начинайте разработку не с синтаксиса, а с нормального менеджера пакетов/зависимостей, в противном случае вашим синтаксическим сахаром останется только подтереться.
Второе. Документация. Это вообще больное место ЯП. Я понимаю, что у многих разработчиков английский не родной, а потому находится в режиме read only, и конструировать английские предложения им по-настоящему мучительно. Но тут действует простое правило: если код не документирован — значит, его не существует. И вот к примеру для Rust'а очень многих крейтов попросту не существует: поленившись черкануть хоть пару строчек документации, их разработчики по сути выкинули свою работу на помойку. Кто ими будет пользоваться, если чтобы в них разобраться, надо лезть в чужой код, в котором даже нет комментариев?
Третье. IDE. Они вносят настолько большой вклад в продуктивность, что если вы предполагаете, будто для вашего ЯП все программы будут писать в notepad'е, то смело затачивайте ваш язык под написание Hello World, потому что на нём и не будут писать ничего сложнее Hello World'ов. Ну, за исключением Language Lock'ов, когда под данную платформу/предметную область других языков вообще не завезли, и все блюют, но пользуются, ибо деваться некуда. По уму, на каждый час, потраченный на работу над компилятором, должно приходится не менее 50 часов на работу над плагинами к популярным IDE (это если не получается потянуть разработку своей собственной IDE, заточенной специально под данный ЯП).
По моим наблюдениям, библиотеки-документация-IDE — это не менее 90% продуктивности, а синтаксический сахар — от силы 10.
НЛО прилетело и опубликовало эту надпись здесь
Сахар разный бывает async/await — очень сильно улучшили продуктивность не только в C# но и JavaScript.
А теперь Kotlin показывает, что не обязательно надо выражать асинхронность в системе типов (Task[T], Future[T]) и иметь какие-то специальные инструкции. Можно писать асинхронный код как обычный. По крайней мере идея такая и реализация похожа. Идея интересная и может стать стандартом.

Это все хорошо ровно до тех пор когда у тебя из-за асинхронности не начинаются data race. А если асинхронность может привнести любая вложенная функция (скажем, Math.Abs) то получается что data race может начаться внезапно после обновления какой-нибудь библиотеки.

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

То есть асинхронность в системе типов всё-таки выражается

Вот только код при этом пишется полностью как синхронный. Посмотрите примеры. И выражается это добавлением одного ключевого слова к сигнатуре метода.

А как тогда такой метод привести к свободной функции (замыканию / делегату / колбеку) без потери существенной информации?


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

Что-что сделать? Зачем приводить один тип функции к другому? Либо я как то не так ваше сообщение распарсил.
Ну и да, сигнатуры функций это часть системы типов.

Полностью согласен. Но вообще изначальное сообщение выглядит как
не обязательно надо выражать асинхронность в системе типов (Task[T], Future[T]) и иметь какие-то специальные инструкции

Хз что автор имел в виду под специальными инструкциями, но никаких Task[T], Future[T] и подобных использовать действительно не нужно. Использовать подобное можно, подходит неплохо для случаев когда нужно колбеки к корутинам адаптировать, но совершенно не обязательно.
Автор имел ввиду, что не надо как-то специальным образом работать с результатами асинхронных вызовов по сравнению с синхронными. Чтобы продолжить вычисления не нужно ни `map`, ни `flatMap`, ни do notation никаких. Потому что работаем с T, а не с Future[T].
Специальные инструкции — методы этих специальных типов представляющих результаты асинхронных вызовов.
А что конкретно вы имеете в виду? Я имею в виду, о чём в Kotlin нужно почитать, чтобы ознакомиться с их подходом? Спрашиваю из интереса :)
Сахар разный бывает async/await — очень сильно улучшили продуктивность не только в C# но и JavaScript.

Ага, разный. Поход за «простой асинхронный код» в JS дал нам решения а-ля redux-saga (и это не единственная штука), которые просто заворачивают в async вообще всё не глядя. А потом этот «продуктивно написанный код» внезапно начинает тормозить, отрисовывая жалкую тыщу простых элементов UI, потому что асинхронные вызовы в JS гораздо медленнее обычных.

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

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

Redux-saga — это плохой пример асинхронного кода (как и Observables). Скорее даже антипример чем пример. А вот интерфейс, основанный на async-await, — это хороший пример.

Практически любые вещи бывают «плохими» в одном контексте и вполне «хорошими» в другом.

Если нет фичи — значит, её нельзя использовать неправильно или избыточно. Меньше фич — меньше «неправильного». Так что ли? Почему виноваты асинки, а не авторы redux-saga?

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

Речь как раз и идёт о том, что «продуктивность разработчиков» в среднем чаще противоречит «продуктивности/производительности кода», чем способствует. И что говорить о том, что писать стало красивше и веселее и умалчивать о цене этой красоты и веселья — это лукавство.

Несколько этапов умалчивания на разных уровнях (от инструментов до продуктов) — это именно то, что в итоге порождает ситуации «ой, а у нас чёт наш красивый код на саге тормозит».
async/await — это не «сахар», это нововведение с куда большим эффектом: они позволилили записать асинхронную подпрограмму — т.е. подпрограмму, выполняющуюся хоть и с перерывами на ожидание внешних событий, но последовательно — в виде именно последовательного целостного куска кода, а не цепочки из маленьких кусочков этого кода — «континуаций тасок», обернутых в загромождающие код вызовы функций ContinueWith/then.
позволилили записать

Это и есть синтаксический сахар в чистом виде.

а ассемблер это в чистом виде синтаксический сахар над машинными кодами…
а Си это синтаксический сахар над ассемблером…
...


Странно почему вы с таким подходом не программируете напрямую в машинных кодах… зачем вам этот синтаксический сахар?

Мне кажется вы слишком напряжены. Расслабьтесь, попейте чайку с сахаром. Я тоже люблю сладкое.

Конкретно в Rust async/await — это не синтаксический сахар, с его помощью можно написать функцию, которая между моментами возобновления работы держит ссылки на локальные переменные. На комбинаторах футур это не выразимо.

То есть просто не даёт сборщику мусора прибить эти переменные или что-то другое?

Вы неправильно поняли, в Rust нет сборщика мусора.

Это и есть синтаксический сахар в чистом виде.

Нет, async/await — это новая семантика: новый (и весьма полезный) уровень абстракции. Благодаря этой конструкции пограммисту не приходится думать, как асинхронную, то есть, прерывающуюся на ожидания, программу разбить на непрерывные части и как организовать связь этих частей — текст программы при использовании этих конструкций выглядит непрерывным.
Аналогия с ассемблером и с Си, которая вам чуть выше не понравилась — она хорошо поясняет, как выглядят такие вот полезные абстракции. В языке ассемблера благодаря мнемоникам команд не приходится запоминать их коды, а символьные метки команд и полей данных позволяют переложить заботу о вычислении смещения до них на программу-ассемблер. Ну, а в C реализованы другие абстракции, более высокого уровня. В частности: трансляция выражений снимает необходимость в детальном описании их вычислений, описания локальных переменных позволяют не задумываться о распределении для них памяти на стеке, а разнообразные операторы управления (if-then-else и т.п.) позволяют более наглядно записать алгоритм, нежели если бы програмист был ограничен только командами условного и безусловного перехода.
Главное, что есть в полезных абстракциях — они снижают сложность программы, убирая детали реализации на более низкий уровень (и обычно — автоматизируя реализацию этих деталей). И конструкция async/await вполне попадает в число таких полезных абстракций.
Нет, async/await — это новая семантика: новый (и весьма полезный) уровень абстракции. Благодаря этой конструкции пограммисту не приходится думать, как асинхронную, то есть, прерывающуюся на ожидания, программу разбить на непрерывные части и как организовать связь этих частей — текст программы при использовании этих конструкций выглядит непрерывным.

Это настолько же новая семантика, насколько do-нотация — новая семантика над методами >>=, pure и так далее.

Не могли бы вы пояснить свою мысль на примере какого-нибудь другого языка, желательно — с императивной парадигмой. Например — обсуждаемых в этой ветке комментариев C# и JS?
А то я недостаточно знаю (точнее, практически не знаю) Haskell, чтобы вообще оценить, вносит ли do-нотация новую семантику, или же это — типичный «синтаксический сахар». В результате я даже не смог понять, что именно вы хотели сказать своим ответом, не говоря уж о смысле аргументации.
Не могли бы вы пояснить свою мысль на примере какого-нибудь другого языка, желательно — с императивной парадигмой. Например — обсуждаемых в этой ветке комментариев C# и JS?

Тут уже мне сложно, я не знаю ни C#, ни JS достаточно хорошо, чтобы писать там адекватный код.


А то я недостаточно знаю (точнее, практически не знаю) Haskell, чтобы вообще оценить, вносит ли do-нотация новую семантику, или же это — типичный «синтаксический сахар». В результате я даже не смог понять, что именно вы хотели сказать своим ответом, не говоря уж о смысле аргументации.

Смысл в том, что


foo arg = do
  val1 <- smth arg
  val2 <- smthElse val1
  pure (val1 + val2)

тупо компилятором по некоторым синтаксическим правилам дешугарится в


foo arg = smth arg >>= \val1 -> smthElse val1 >>= \val2 -> pure (val1 + val2)

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


Насколько я отрывочно знаю JS, async/await под капотом точно так же дешугарится в код с промисами и коллбеками в then.

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

Меняется семантика или нет — это, на самом деле, зависит от точки зрения: на каком уровне абстракции (которых в современных программах не один) оценивается семантика программы. На самом нижнем уровне — том, с которым имеют дело процессор и другие устройства компьютера, — семантика, естественно, не меняется: эквивалентность программы должна сохраняться. Но вот на более высоких уровнях абстракции, с которыми работает не компьютер, а программист (или компилятор), семантика, выраженная в терминах абстракций этого уровня, может быть другой. И я именно про эти, высшие, уровни говорю.
В нашем случае при использовании async/await программист видит асинхронную функцию как обычную для него последовательную императивную программу, которая в местах, где нужно подождать, просто становится на паузу и освобождает процессор. За кадром при этом, естетвенно, происходит вызов планировщика. Этот вызов извещающает планировщик, что программа, прежде чем станет готовой к работе, должна дождаться завершения некоей другой операции и сообщает детали, нужные для ее возобновления. И детали этого вызова могут находяться на более низком уровне абстракции, чем тот, на котором работает программист, и в случае async/await это действительно так. Потому что важной частью этих деталей при вызове планировщика promise/Task является указание места, с которого надо потом программу запустить, т.е. какой учаток кода выполнять следующим (так уж устроен этот планировщик). Но программист, пользующийся async/await, избавлен от указания этих деталей: на его рабочем уровне абстракций программа выполняется последовательно. Ну, или — в соответствии с операторами управления (условным, цикла и т.п.), имеющимися в программе, но, в любом случае — так, как будто после ожидания управление возвращается на оператор после await — то, чего планировщик на более низком уровне абстракции на самом деле не обеспечивает.
А вот если программисту приходится обходиться без async/await, то ему приходится при использовании promise/Task работать на этом, более низком уровне абстракции, а потому — указывать (через then/ContinueWith) следующий выполняемый участок своей программы. В результате на этом, более низком, уровне абстракции программа из последовательной превращается в цепочку вызовов функций, каждая из которых вполне императивным образом реализует соответствующий участок.
Насколько я понимаю, в парадигме функционального программирования цепочка вызовов функций (а функции там AFAIK рассматриваются в другом контексте — не как последовательность действий для получения конкретного результата для конкретных значений параметров, а как отображение множества входных значения на множество результатов) — это нормальное положение вещей. Но в парадигме императивного программирования цепочка вызова находится далеко от привычного способа написания программ.
А «синтаксический сахар» — это, на мой взгляд, нечто другое: не более, чем простое сокращение записи тех же самых по смыслу операций. Типичный, на мой взгляд, пример (который я взял, чтобы далеко не ходить, его я сегодня рассматривал на другом форуме) — кусок кода на Powershell (надеюсь, синтаксис там будет очевиден практически любому программисту) для вычисления чисел Фибоначчи:
$a,$b = ($a + $b),$a

что, на самом деле, полностью эквивалентно (оператор «запятая», которой в правой части — это в Powershell оператор создания/расширения одномерного массива) куску кода
$c=($a + $b),$a
$a=$c[0] 
$b=$c[1]

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

PS Чисто для справки. В C# async/await сделан немного по-другому: весь код async-метода преобразуется компилятором в вызовы некоего метода конечного автомата, реализующего весь остальной код, в котором для каждого текущего состояния выполняется нужный кусок кода и состояние меняется на следующее. Первый вызов, для куска кода до первого await, идет синхронно, остальные — после ожидания завершения объекта-операции указанного в соответствующем await (если в await указан Task, то это делается через ContinueWith для для этой Task, что есть прямой аналог then для promise, но там может быть не только Task, так что в общем случае вызов идет через callback). Но логически это работает примерно (не без нюансов, однако) так же, как и в JS — как цепочка promise/continuation.
Если я вас правильно понял, то do-нотация привносит в функциональный в целом язык императивный способ записи ровно той же программы, так?

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


В конце концов, я могу переформатировать пример без do выше во что-то вроде:


foo arg =
             smth arg                                        >>=
    \val1 -> smthElse val1                                   >>=
    \val2 -> pure (val1 + val2)

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


Меняется семантика или нет — это, на самом деле, зависит от точки зрения: на каком уровне абстракции (которых в современных программах не один) оценивается семантика программы.

ИМХО вопрос в том, можно ли преобразовать одну программу в другую по чисто синтаксическим правилам или нет. В случае с do-нотацией и (насколько я знаю) async/await в JS — можно. Это сахар. В случае с async/await в C# — нельзя, судя по тому, что вы пишете. Тут, правда, ещё возникают вопросы о том, можно ли было достигнуть аналогичных эффектов прямым синтаксическим преобразованием в случае C#, и является ли вся эта ерунда с КА лишь какой-нибудь оптимизацией, но это другой вопрос.


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

А вот, кстати, например, в случае C++ лямбды не были чистым синтаксическим сахаром, если добавить их в C++03 и больше ничего не менять. Лямбды в C++ умеют выводить возвращаемый тип, а в C++03 никакого вывода типов для функций не было, поэтому синтаксически преобразовать бы это не поулчилось.

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

Ситуацию с несколькими уровнями абстракций в одном и том же языке можно проиллюстрировать на старом и хорошо известном примере парадигмы структурного программирования (которую, наверное, сейчас изучают все, кто изучает computer science). В свое время (где-то полвека назад) переход к структурному программированию — т.е. построению программ из блоков последовательно выполняемых операторов, объединенных специальными операторами управления — позволил снизить сложность тогдашних программ по сранению с парадигмой «спагетти-кода» из GOTO, в которой было принято писать на языках, не имеющих таких операторов управления в полноценном виде (например FORTRAN IV). Поэтому в современных (и не очень современных, таких как С — тоже) императивных языках имеется полный комплект таких операторов управления (if-then-else, do-while и т.д.), позволяющих легко писать программы в структурном стиле. Но оператор goto при этом во многих таких языках тоже имеется, так что ничто не мешает на этих же языках написать пресловутую «фортрановскую программу» (с соответсвующим увеличением ее сложности). Следуя вашему подходу, все эти структурные операторы управления можно назвать «синтаксическим сахаром»: ведь любую программу с их использованием можно чисто автоматически преобразовать в такую, которая содержит только goto и простейшую форму if (что-то типа if() goto...;) Но вот называть их так, игнорируя тот новый уровень абстракции, который они привносят в язык — это означает затушевывать ту пользу, которую приносит этот уровень. Поэтому называть структурные операторы управления в том же C «синтаксическим сахаром» я считаю неправильным — и, насколько мне известно, их так называть вообще-то и не принято.

Так вот, с async/await ситуация та же самая: программу можно переписать на том же языке без их использования, но при этом теряется не только краткость формы записи (эффект «синтаксического сахара»), но и то содержание, которое они привносят — концепция единой асинхронно выполняющейся подпрограммы вместо спагетти из функций обратного вызова или продолжения — и которое позволяет снизить сложность написания программ.

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

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


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


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


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


Если бы Idris работал, и там был бы один GOTO на все про все — я бы писал на нем. (Ну и да, в ФП как правило нет циклов, а if считается очень дурным тоном).

Как по мне, то в примере с повершелл появляется новая абстракция. Вернее пропадает низкоуровневая — массив. А появляется какая-то анонимная абстракция присваивания списку переменных список значений. Вот в PHP, например, подобный финт не прячет факт использования массива:
[a, b] = [a + b, a], то есть видно, что создаётся и разыменовывается массив. А в вашем примере это любому программисту не очевидно, просто какое-то множественные присваивания.

Мое мнение: абстракция — это само присваивание. А присваивание в одном операторе нескольким переменным, которые потом рассматриваются совершенно отдельно — это чисто сокращение записи.
Код с промисами превращается в кашу и плохо пахнущую кучу. Это уже совсем другой стиль специального программирования, где чтобы передать 1 параметр, нужно пробросить его через кучу функций. Я это называю колбечное программирование.
Т.е., что делается:
i1 = await Task1(i0);
i3 = await Task2(i2);
Work(i1);

Превращается в
Task1(i1,i2).Then(i1,i2 => Task2(i1,i2)).Then(i1=>Work(i1));

Попробовал промисами вот этот пример:
t1 = Task1(i1);
i3 = await Task2(i2);
i4 = Action();
i5 = await t1 + await Task3(i1,i2) + i2 + i3 + i4 + i5;

За несколько минут не получилось придумать как это впихнуть в промисы.

Но под капотом в C# это работает ещё лучше, т.к. может использовать многопоточность, делит функцию на части оптимальным способом, использует меньше проверок while(!complete).

Только вот для кучи проектов моя продуктивность на хаскеле в бесконечное количество раз выше продуктивности на плюсах, потому что некоторые вещи я не возьмусь делать на плюсах. Компиляторы писать, например. Это, конечно, не в синтаксическом сахаре дело, но в чем?


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

Я думаю нужно различать синтаксический сахар и конкретный концепт, скажем pattern matching — это не синтаксический сахар.

Паттерн-матчинг — это всего лишь сахар над typed Church encoding


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

Покажите, пожалуйста, как мне написать обобщённый посетитель для std::variant<T, U> при том, что T и U могут совпадать.

Надо просто заворачивать не в std::variant<T1, T2, …>, а в std::variant<Label<1, T1>, Label<2, T2>, …>.

Ну то есть опять костыли. Понятно.

В плюсах без них никак.


И это вы ещё mach7 не видели.

И это вы ещё mach7 не видели.

Видел, но реализацию не смотрел. И, видимо, хорошо, что не смотрел.

По уму, на каждый час, потраченный на работу над компилятором, должно приходится не менее 50 часов на работу над плагинами к популярным IDE (это если не получается потянуть разработку своей собственной IDE, заточенной специально под данный ЯП).

Я очень рад, что разработчики многих (большинства? почти всех?) языков программирования так не делают. Для большого спектра применений программирования хватит либо простейшего плагина к какому-нибудь vs code, либо жупитер ноутбука. При этом соотношение потраченного авторами времени на разработку языка vs работу над IDE как бы не обратное вашему получилось.
Конечно, я не спорю что при прочих равных хорошая IDE — полезная и удобная вещь. Но уж никак бы не предлагал так ставить её на первое место, скорее наоборот — поворачиваться в сторону серьёзных IDE тогда, когда язык уже стал реально использоваться людьми.


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

А вот этот пункт поддерживаю, библиотеки — сила :)

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

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


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


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


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


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

У вас в опыте не было фич, которые занимают годы, а не месяцы. Из своего опыта вы делаете вывод, что вся разработка одинаковая. А она разная.

Разработка языка — это все-таки не фича. Это весь проект скорее. Проект состоит по сути из архитектуры основной и набора фич. По крайней мере в моей голове. Так вот проекты идут и 3 и более лет в моей жизни тоже. Ни одна фича не может занимать сама по себе более 3 месяцев. Это либо плохое разбиение на фичи, либо я не знаю что…

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

Если то, что происходит в мире не соответствует тому, что происходит в вашей голове, это проблема мира, ага.


Так вот проекты идут и 3 и более лет в моей жизни тоже.

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


Ни одна фича не может занимать сама по себе более 3 месяцев.

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


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

Примеры будут? Обратный пример — добавление джененериков в ту же Джаву. Тоже был многолетний труд.

Scala — 3 года (2006 версия 2.0)
С# — 3 года (2005 версия 2.0)
Я понимаю разницу между аддитивными фичами и мультипликативными. Равно как и понимаю, что сложность реализации (и тех и других фич) сильно зависит от архитектуры и качества кода. В тех языках где об этом думали это было сделано за 3 года.

Если бы Роб Пайк не занимался своим культом «простоты» c 2012 года (версия 1), а думал бы лучше, как сделать дженерики в будущем, то у нас они были бы уже в 2015. А сегодня 2020, а их все нет…
Как уже говорили выше, «до сих пор не сделана фича X» без указания, какие фичи были сделаны — фигня какая-то. Есть мнение, что товарищу Пайку было чем заняться без беспрестанного обдумывания, как сделать дженерики в будущем.

Ну вот, а то "три месяца", "три месяца". Годы же.


3 года и 8 лет — это величины одного порядка. Можно считать равны для проектов типа языков программирования.

Так посмотрите, сколько еще всего было выкачено в этих релизах 2.0. Если условно говоря поделить эти 36 месяцев на все фичи, то там где-то по 3 на штуку и получится.

Эм, так вы говорите, что девять женщин выносят ребенка за месяц?

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

Помню, у меня в одной из программ для компилятора PL/I версии (O) был цикл с управляющей переменной типа файл, но некому было оценить эти изыски. Начальство, как ни странно, волновал только продакшен. А теперь я сам начальство, и мне пофиг, на чём пишут программисты. Так устроена сансара :(
Забавно, но с высоты сегодняшнего времени непонятно, что там в PL/I было такого уж сложного, что его изучение было доступно лишь единицам.

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


Одно только описание синтаксиса и семантики оператора DO в PL/I(O) — уже достаточно занимательное чтиво, а оператор DECLARE — вообще божественен (я думаю, страниц 20 занял бы в БНФ, если бы кому пришло в голову писать БНФ для PL/I).


Ах да, ещё ПРЕПРОЦЕССОР! Лично я освоил сам первичный язык PL/I(O), изучил все опции трансляции, но сломался на запоминании отличий операторов препроцессора от таких же по названию операторов первичного языка.


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


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

А потом появился C++...

C++ появился относительно простым, и обрастал жиром 37 лет (как не хочет автор).
Если бы С++ появился на свет сразу жирным (как хочет автор) то С++ был бы примерно там, где сейчас находится PL/1

Что-то вспомнилось от создателя Algol, что осознается как ошибка на миллиард, и тащится до сих пор везде — зачем нам null — но его было так просто реализовать

В JavaScript вон вообще два разных null-а (null и undefined). Жуть страшеннейшая, криво, неудобно, но все с этим живем. А PHP начинал как язык без null, там был только false. Но быстро исправились, хотя многие стандартные функции все еще возвращают false по старинке там, где должен был быть null.

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

Веселье начинается, когда нужно различать "пустое значение"(0), "отсутствие значение" (undefined), "стёртое значение" (null) и "ошибочное значение" (NaN).

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

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


Нет никакой диктатуры. Просто у того, кто принимает "фичу" к реализации есть еще и необходимость ее дальнейшей поддержки и интеграцией с другими фичами, которой у того кто ее предлагает нету. И языки здесь не единственные — если поддерживаешь небольшой собственный open-source проект будет то же самое. Ты не будешь реализовывать каждую мелочь которая к тебе в issues в гитхабе попадет — будешь взвешивать каждую на весах "сложность реализации — сложность поддержки — полезность"


Ну а так многие языки открыты а компиляторы open-source — бери да добавляй фичи. Хотя бы для того чтобы понять — действительно ли это такая простая фича как кажется.

Именно вот это же самое про новые фичи языка постоянно говорит в своих докладах разъезжающий по миру Брайан Гетц.
Например:


На конференции по Closure в 2014 году
Автор не те языки использует. По моему мнению языки бывают «программисткими» и «административными». Программисту нужно написать программу а писать лень. В результате он придумывает язык программирования который решает эту задачу. У таких языков большие возможности и удобство по быстрому написанию кода, хотя они сложнее в обучении. Философия языка: TMTOWTDI. Программы получаются короткими и быстрыми. Это языки программистов для программистов. К таким языкам относятся: C, Perl, Ruby, php, Rust.
У «административных» языков обратная задача. Начальнику хочется повысить свой статус. А он выше чем больше у него работает программистов. Соответственно язык создаётся кастрированным, неудобным, требующим много лишней писанины, текст программы забивается ненужными проверками. Никаиж удобств. Больше строк — больше ошибок — дольше отладка. Правда языки эти просты как валенки и не требуют серьёзного обучения.
За них платят. Программистам тоже польза — больше строк больше оплата, выше статус. Ведь написать программу на языка у которой нет фичи сложнее чем на языке в которой она есть. Поэтому неприятие «сахара» так как он упрощает и ускоряет написание программ. К таким то языкам и относятся выбранные автором: Java, Go, Python и т.д. Java вообще гениальный язык. На первый взгляд он прост но даже студент не смог бы написать более медленный в написании и исполнении язык. Внимательно изучив его можно понять что он спроектирован очень грамотно для замедления работы.
НЛО прилетело и опубликовало эту надпись здесь
Я на C# пишу но считаю что он где то посередине. На остальных писал.
Слишком уж толсто

Я одного не понимаю: неужели троллинг про перформанс джавы воскрес?

Да! У меня это прямо в голове крутилось. Что мы вот прямо сапожники без сапог и есть.

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


Ещё я теперь лучше понимаю, почему мне C# нравился гораздо больше и писалось на нём гораздо проще, чем на Java, несмотря на отсутствие (в то время) нормальной кросс-платформенности, а сейчас, когда она есть, писать на нём ещё приятнее и быстрее.


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

Очень вас прошу — попробуйте теперь F#. Я после него забыл думать, что C# — хороший язык.

О, да вы в начале пути!

В смысле я? Я прошел по кругу С++, Python, C#, Java, F# и сейчас Scala (+ тулы на Go — но в этом стыдно признаваться)

Ну после F# (или после Scala) можно углубиться в хаскель, а потом в вещества ещё потяжелее.

Это далеко не всех вставляет.

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

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

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

По этой причине не вижу особого смысла в обсуждении обозначенной проблемы в силу ее крайней субъективности. Автору же можно посоветовать вписаться в крупный проект для приобретения нового жизненного опыта. Вот немцы тоже давно обсуждают, что негоже числа произносить задом наперед (вместо «двадцать два» они говорят «два и двадцать» одним словом), но до сих пор не могут что-то изменить в этом казалось бы на первый взгляд простом вопросе, хотя при этом особо не страдают от отсутствия синтаксического сахара в немецком языке.
Слушайте, я за 16 лет разрабытвал всего очень много: от игр для XBox и PS2 (год на игру), до систем алгоритмического трейдинга (по 3 года дважды). И на галерах бывал и ценным ключевым сотрудником работал. Как-то за отсутствие разнообразия и больших проектов в моем опыте на меня еще никто не набрасывал.

Я/МЫ — я просто не очень комфортно чувствую себя выражаясь от лица всех — меня никто не уполномачивал. И скорее всего, «МЫ» не существует.

Мое решение, которое я бы не хотел пушить на всех: менять стеки и уметь хорошо разрабатывать хотя бы на 2-3 стеках. Но это только смена правил.
Ок. Попробую уточнить свою позицию. Для меня важно лишь то, что человек СДЕЛАЛ, что ему помогло добиться результата, что ему мешало, и как он смог обойти препятствия. Также интересен неудачный опыт, но опять же в ключе что было СДЕЛАНО, что помогало и что мешало.

Вы же указываете лишь на сферы Ваших интересов и Вашей деятельности, при этом не уточняя реальные проблемы, связанные с ограничениями того или иного языка, с которыми Вы лично сталкивались, и которые не смогли преодолеть. То есть нет даже намека на СДЕЛАНО. Уж извините, но жалобы на отсутствие фичей в том или ином языке для меня относится к области «на вкус и цвет товарища нет».

Просто в своей практике мне приходилось сталкиваться с ситуациями, когда некий программист вовсю расхваливает C# и чморит Java, но при этом не может сделать нормальные индексы в MS SQL. Другой программист топит за TypeScript и модные фреймворки и воротит нос от классического JavaScript, но при этом не может внятно сформулировать, какие преимущества дают его любимчики для конкретного прикладного решения, а то, что переход требует времени и денег, его вообще не колышет. Третий же пишет на Java, ориентируясь на версию 1.2.2, создавая под себя необходимые библиотеки, но при этом у него все летает и сидят довольные пользователи.

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

P.S.: Хотя я сам был бы рад опциональной типизации и поддержке интерфейсов в JavaScript.
Другой программист топит за TypeScript и модные фреймворки и воротит нос от классического JavaScript, но при этом не может внятно сформулировать, какие преимущества дают его любимчики для конкретного прикладного решения, а то, что переход требует времени и денег, его вообще не колышет.

Я вам больше скажу: я лично видел одного программиста, горячо топившего за Typescript всеми конечностями, но у которого при этом в его коде более 50% всех типов были any. Когда я этого совсем не понял, и попросил у него пояснений, в ответ мне было сказано примерно следующее — «я же вижу, что это стильно модно молодёжно, да, я многих вещей в TS нифига не понимаю, и он какие-то странные ошибки мне говорит, когда я не юзаю any, но я же стараюсь и когда-нибудь я в это всё смогу и осилю!».

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

Самое забавное в современных языках то, что они все воруют синтаксичейский сахар у древнего языка Nemerle, который написали трое студентов по фану, уже лет *дцать и все еще сильно отстают от него… Ближе всего к нему, пожалуй, c#, но сколько еще лет нам ждать новыхстарых фич?

А можно поподробнее. Какие именно фичи впервые появились в Nemerle?
Гигиенические макросы, сопоставление с образцом, вывод типов?
Всё это было задолго до Nemerle. Я что-то упускаю?
Как и любая другая разработка софта, процесс внесения изменений в язык программирования должен быть предельно прост: пожелания пользователей (то есть нас — программистов) изучены, задача поставлена, адекватные сроки определены, извольте выполнить в срок.

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

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


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

Здравствуйте, не хотите поговорить о Rust?


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

Здравствуйте! На самом деле я Раст сознательно не разносил в посте. Во-превых, не знаю в чем его недостатки, очень мало игрался, но очень хочу. Во-вторых, на первый взгляд у него нет недостатков :) В-третьих, его сообщество выглядит действительно реальным а не бутафорским.

Вот только что в голову приходит. Вот, например, Go мы обсуждаем. А почему он есть вообще? Почему Rust его не убил. И кроме гугла, есть одна забавная причина — Go выбрали как язык для DevOps. Очень много тулов на нем написано и вцелом идет процесс замещения Python на Go у DevOps. Я спросил у них (DevOps'ов) почему не Rust или что-то другое? Ответ был такой: Rust немного сложноват своим борроунгом, если бы этой «лабуды» не было, то мы бы писали на нем скрипты и тулы. И вот я думаю, нельзя ли сделать так, чтобы бороунг был опциональный, типа если пишешь без него, то какой-то там Боэм GC включается и все норм.

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

Вы спросили можно ли — я ответил, что можно, и показал пример.


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

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

А как вы доли рынка считаете, кстати? А то я погуглил «f# market share», и по первой ссылке было что-то про меньше 0.01%. Там кривая ссылка, конечно, и она рассматривает только веб-разработку, как я понял, но вопрос методологии таки поднимает.

Например личные ощущения. Т.е. я например имел дело с раст и F# вакансиями, но ни разу нигде не видел ни одной коммерческой работы с D. Хотя уверен, что она есть.


Тот же F# вот в среде дотнетчиков активно форсится, обсуждается и порой применяется в C# проектах.

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

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

Это фундаментальная фича языка, на которую завязан дизайн вообще всего. Без borrow checker останется няшный Си с другим синтаксисом.

Go выбрали как язык для DevOps.

А почему именно Go выбрали девопсы? Потому что он очень простой. Потому что Роб Пайк не сделал генерики (а еще исключения, классы...)

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

Это классно лишь, когда задачи не пересекаются. Но такого не бывает. Так что типичная ситуация: язык подходит для задачи на 80% и не хватает 20% из другого языка.

Во-вторых, на первый взгляд у него нет недостатков :)

Чувствуется, что вы на Rust не писали. Я навскидку легко могу назвать пяток недостатков, которые реально мешаются. Причём приличная часть претензий будет сводиться в основном к просто не стабилизированным API стандартной библиотеки.


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

Это так не работает. Во-первых, влияние borrow checker чувствуется практически во всех фичах языка (в частности, именно поэтому в Rust 3 трейта под функции, а не 1), Если сделать его опциональным, то у вас будет фактически два параллельных языка. Во-вторых, borrow checker — это далеко не только про память. В-третьих, если сделать borrow checker опциональным, то у вас экосистема расколется на две весьма неравные части: ту, в которой разработчики используют borrow checker, и значительно большую ту, в которой не используют. В итоге, если вам понадобится библиотека, которая не будет использовать GC, то у вас будут значительно меньшие шансы её найти.

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

Кстати, портировать один скрипт (плагин для вима) со второго питона на третий я так и не осилил. Правда, питон я не знаю, но это неважно.

Неосилятор! /s

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

Культ языка программирования, чаще всего, агрессивный. Я помню как в конце нулевых я пытался объяснить джавистам, что их язык отстал от C#. Вместо вдумчивых обсуждений нужны ли в языке лямбда-функции (C# 3.5 2007) я встречал агрессию, усмешки и снисходительные комментарии в духе: «мелкомягкие все скопировали у богов».
В Stack Overflow в вопросах вида “как сделать в Java X” именитые участники сообщества отвечают, что X вреден и делать так ни в коем случае не надо, а то что язык такого не позволяет — это величайшее благо, ибо защищает программистов. Такие комментарии люто заплюсованы. И наоборот: заминусованы те, что находятся не в канве основной линии партии.
Ох, как я вас понимаю.
Недавно пытался в сообществе Dart/Flutter разработчиков донести, что хорошая тема писать на Provider+ChangeNotifier — в ответ просто поток высокомерия и хамства в духе: «Redux — это серьёзный-пресерьёзный тыртырпрайз, тебе дилетанту не понять, а Provider — какая-то индусская хрень».
Люди до сих пор дрочат себе мозг с Redux и Bloc, ещё и новичкам их советуют. Хотя эти паттерны морально устарели, и получаются тонны мутного кода. Похоже, у некоторых к 30 годам уже мозг закостеневает, и неспособны воспринимать новые идеи.
Так что плюйте на всех, пишите как вам нравится, и берегите нервы.
Я лишь немного потыкал пару React+Redux и код жутко мозголомный получается на первый взгляд. Но когда я в плагине браузера увидел что могу двигать состояние визуалки вперед назад во времени (и с возможностью вроде продолжить с любого места) просто прозрел, в других средах это практически невозможно повторить. Цена для такой мощной отладки UI\UX думаю обоснованная.
Wayback machine нужна далеко не всегда и не всем, а даже когда она нужна — в большинстве случаев её отлично можно реализовать «сбоку» (отдельным модулем), а не частью архитектурного решения всего проекта.

Брать редакс только потому, что «undo-redo стейта — это ж так клёво!» — это тот еще маразм.
Если этот механизм рабочий и не ломается от hot update то написание анимаций, переходов и прочих сложных изменений состояния должно быть сказкой — т.е. производительность труда при разработке визуалки должна стремится в космос. Я именно такой профит увидел. Хотя тут и фронтенд разработчиков в пору пилить на frontend-UI и frontend-back ибо redux реально мозг вскрывает
А вывод-то какой? Просто поныть в стиле филипакарта (или как там его)?
Не все чувствуют в себе обязанность выдать всем по выводу. Но раз вы попросили…
Я думаю — менять стеки и хорошо владеть 2-3 это хорошо. По крайней мере когда достает один, можно на другой перейти и так далее.
А можно и поныть — тоже помогает.
Что значит «всем по выводу»? Одна статья — один вывод в конце. Очень полезно, даже если в самом материале автор «растекается мыслью по древу» (особенно так, что древа уже и не видно).
можно и поныть — тоже помогает
Кому? От чего? :)
Мне помогает — видеть, что у других людей аукается и у них такие же проблемы — как-то психологически помогает.

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

Но вам то как мой вывод? Надо — не надо менять стеки? Есть такая тема среди разрабов — многие считают, что надо десятилетия окапываться в одном стеке. Я сейчас думаю, это вредная стратегия для самих разрабов и сообщества вцелом, в том числе потому что такие разрабы в итоге формируют культ описанный.
Мне? :) Уж не обижайтесь, но мне видится, что за 16 лет (это много что ли?) у вас количество не перешло в качество, вы как были простым программистом, так и остались. Собственно, поэтому и остались, потому что не перешло. Вы ничем не руководили, архитектуру не разрабатывали, угадал? (может и нет, но буду сильно удивлён). Вот и не видите дальше собственного носаых разработок. Вы даже не задались вопросом почему языки развиваются именно так, как развиваются, а просто сделали выводы «да влом им там всем всё!» и «ну туууупыыыыыыыые».
Не обижаюсь. Но нет — не угадали. Тяну водиночку практически весь переезд из легаси монолитов на микросервисы и масштабируемую архитектуру в облаке организаций 50-100 разработчиков на последних двух местах работы, вообще меня специально для этого нанимают нынче и дают погоны «Principal Software Engineer». Разрабатывал системы высокчастотной торговли и просто торговли в крупных банках. Был тимлидом еще 10 лет назад. Создатель FSharp.Json — единственной норм либе для JSON в F#. Да много понтов можно кинуть.
Нет. Определённо нет. Разработчики языков, действительно, консервативны, и на то есть веские причины. Любая внедрённая в язык фича — нагрузка на разработчиков, которые обязаны знать все фичи языка, которым пользуются (иначе они не смогут адекватно работать с чужим кодом). Любая внедрённая в язык фича — нагрузка на разработчиков компиляторов, без труда которых вообще не будет никакой разработки. Это в теории «ну пусть напишут компилятор получше!», а на деле есть определённые сроки и деньги, после которых создание средств разработки становится бессмысленным: проще взять менее навороченный язык. Многие языки утонули только из-за того, что они стали как баржи, перегруженные дерьмом.
(задумчиво) автор предлагает переизобрести algol68 или я чего-то путаю?
Это действительно проблема многих языков, но не всех. Мне нравится подход PHP, в этом плане, каждый может предложить свой RFC, грамотно оформив его и предложив варианты реализации. Далее идет голосование стейк холдеров PHP и по итогу фичу применяют или нет. Притом всегда ведутся дискуссии, предлагаются новые варианты если голосование не прошло. Десятки людей вовлечены в процесс и пытаются найти лучшее решение.
Пример: wiki.php.net/rfc/union_types_v2

Так же, не вижу проблем у Kotlin, в язык постоянно добавляют сахар\конструкции\инструменты для разработчиков, и лично мне этот язык дает даже больше, чем я хотел.
Мне нравится подход [...] каждый может предложить свой RFC
не вижу проблем [...], в язык постоянно добавляют сахар\конструкции\инструменты

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


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

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

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

Да компилятор усложняют, но не всегда это плохо. Введение типов в PHP 7.4 замедлило компилятор на 1-3% при включенной типизации, если мне память не изменяет, но с другой стороны появился, type safety.

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

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


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

Забавно, что вы в "синтаксический шлак" записали в основном семантические фичи.

с другой стороны появился, type safety.

Type safety — это статическая штука, а в PHP проверки типов, насколько я знаю, динамические.

Спасибо, ошибся, имел введу концепцию в целом, что это позволяет писать безопасный код с точки зрения типизации.
Автор взял три языка (Java, C#, Go), которые были разработаны корпорациями для своих целей — и поставил им в претензию… то, что они были разработаны видите ли корпорациями(!), видите ли в своих целях!

Ну так а что вы хотели? Кто платит, тот и заказывает музыку.

Хотите свободы — идите в мир C++. Там нет одной монопольной корпорации, в комитете по стандартизации 600 человек, куча конкурирующих компиляторов, любой человек может сделать proposal в стандарт и добиваться его принятия (и многим удаётся).
куча конкурирующих компиляторов

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