среда, 24 августа 2022 г.

[prog.flame] Еще раз о сложности C++. Аналогия со сложностью высшей математики

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

Одним из регулярно встречающихся аргументов против C++ выступает "а вы видели, что криворукие программисты на плюсах вытворяют?"

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

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

Сегодня хочется сказать про другое.

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

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

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

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

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

Но мне не приходит в голову говорить, что ТФКП -- это говно, потому что сильнасложна и нивазможнаасилить.

Нет. ТФКП -- это сложно, потому что это было разработано для решения сложных проблем. Просто моих мозгов на ТФКП не хватает.

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

C++ сложен. Так уж получилось.

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

И да, раз уж инструмент сложен, то не всем хватит мозгов осилить C++. Ну вот мне с высшей математикой же не хватило. И это нормально.

Причем то, что люди чего-то не могут освоить, в том же образовании известно давно. Не просто же так появились вступительные экзамены и экзаменационные сессии. Как раз для того, чтобы и заранее, и в процессе, отсеивать тех, кому тупо не хватает мозгов (и/или самодисциплины, и/или интереса) для изучения преподаваемых предметов. И как бы народ привык, что такая фильтрация -- это и нормально, и правильно. Лучше ничего еще не придумали вроде как.

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

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

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

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

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


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

PPS. То, что человеку не хватило ума освоить C++ (или Haskell, или Agda, или SQL, или еще что-то) вовсе не означает, что он умственно отсталый. Он просто недостаточно хорош именно в этом. Но может быть чрезвычайно одарен и продвинут в других областях, в той же математике, например.

PPPS. Я сам современный C++ уже понимаю далеко не всегда и везде. Какие-то места просто запомнил, к каким-то даже не приближаюсь. Но, за счет большого багажа, более-менее успешно применяю то, что знаю, без особых проблем. И не факт, что мне удалось бы освоить современный C++ начни я его изучать сегодня.

4 комментария:

Alex комментирует...

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

eao197 комментирует...

@Alex:

> к сожалению аналогия не слишком хорошо работает.

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

> На что наступают сразу - срезка, копия тяжелых объектов.

Тут логично было бы задать вопрос: а как сделать иначе в языке с продвинутым ООП и отсутствием сборки мусора?

> Синтаксис шаблонов который был сделан специально сложным для на то время новой и непривычной функциональности.

Забавно, что когда приходится читать много кода подряд (как старого своего, так и чужого), то многословный синтаксис C++ (особенно в части шаблонов) оказывается для меня во благо. Когда сам пишешь код, то все эти template, typename и forward раздражают. Но когда читаешь, то эти же самые ключевые слова позволяют лучше ориентироваться в том, что написано. Особенно когда глаз уже замылился.

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

> с++ сложен для простых вещей

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

> а для многого вообще убог (например рефлексия).

Конкретно для рефлексии он не убог, он вообще не приспособлен.
Вот когда рефлексию завезут, тогда и можно будет судить. Но, подозреваю, что там будет не столько убогость, столько чрезмерная сложность (наглядный пример -- модули в C++20).

Alex комментирует...

>Тут логично было бы задать вопрос: а как сделать иначе в языке с продвинутым ООП и отсутствием сборки мусора?
я не говорил о причинах (они понятны) или о том как это сделано в других языках (мало что знаю) а только о фактах в с++ - передача параметров слишком сложна.
как сделать иначе - вопрос непростой. Например над свифт трудился в том числе известный плюсовик Дейв Абрамс и получилось по-другому (да, там есть счетчик ссылок).
Может быть что-то типа маркеров in (immutable) out (mutable), inout (mutable). а дальше какие-нибудь трейтсы опрелят лучший способ передачи (референс или по значению). как сюда вписать move семантику - не знаю.
> Сильно зависит о того, если ли для этих простых вещей готовые библиотеки или же все нужно педалить с нуля и на коленке.
я имел ввиду базовые вещи языка - инициализация, передеча параметров и т.д.
> Конкретно для рефлексии он не убог, он вообще не приспособлен.
ну ок. возьмем сериализацию. и упираемся в самодельную рефлексию.
---
я привык за много лет (взрослея параллельно с плюсами) но для новичков это боль.

eao197 комментирует...

@Alex

> как сделать иначе - вопрос непростой.

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

- передаем по значению (копия мутабельна);

- передаем константу по значению (копия константна);

- передаем по мутабельной ссылке;

- передаем по константной ссылке.

Для всего этого нужны средства выражения. И как раз тот факт, что можно передать по значению, а можно передать по ссылке и ведет к проблемам. Типа срезки. Избавиться от таких проблем можно только запретив вариативность значение/ссылка. Но без такой вариативности не будет эффективности. А если мы забиваем на эффективность, то и C++ не нужен.

> я имел ввиду базовые вещи языка - инициализация, передеча параметров и т.д.

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

> ну ок. возьмем сериализацию. и упираемся в самодельную рефлексию.

Так с сериализацией та же ситуация, что и с рефлексией. Нету ее :)

> я привык за много лет (взрослея параллельно с плюсами) но для новичков это боль.

Мне когда-то в 90-е довелось свои контейнеры велосипедить за неимением STL везде, где хотелось иметь STL. И собственные умные указатели.

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

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

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

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