?

Log in

No account? Create an account
о современном C++ и его сложности - Поклонник деепричастий [entries|archive|friends|userinfo]
Anatoly Vorobey

[ website | Website ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

Links
[Links:| English-language weblog ]

о современном C++ и его сложности [сент. 16, 2017|06:28 pm]
Anatoly Vorobey
[Tags|]

(будет интересно программистам на C++ и вряд ли кому еще)

Автор заметки std::visit is everything wrong with modern C++ несколько преувеличивает масштабы проблемы, но проблема тем не менее существует и реальна. Он пишет про новый тип std::variant в C++17, который позволяет сохранять в одном значении один из нескольких разных типов. В старом добром C такое делали втыканием внутрь структуры одновременно union и переменной, означающей, какой из членов union реально присутствует. std::variant позволяет добиться примерно того же, но с статической проверкой корректности. При том, что проверить наличие конкретного варианта внутри std::variant легко и понятно с помощью std::get, хочется также иметь возможность сделать аналог switch, выполняющий разные действия для разных вложенных вариантов - так, чтобы компилятор проверял, что все варианты указаны. И вот это, пишет автор, комитет по разработке C++17 сделать убедительно не смог - либо надо писать громоздкий класс с переопределением оператора вызова (), либо вообще заниматься какой-то прикладной магией типа рекурсивных темплейтов.

С одной стороны, он прав. В том виде, в каком std::visit сейчас существует, им неудобно пользоваться, и это упущение со стороны комитета (которое, возможно, будет исправлено). Но он неправ, когда пишет, что эта ужасная сложность самого языка показывает, что C++ двигается в неправильном направлении... это поезд, который давно ушел. C++ был слишком сложным языком для простых смертных в 2014-м году. До этого он был слишком сложным языком для простых смертных в 2011-м году, а до этого он был слишком сложным языком для простых смертных в 1998-м году, и сказать по правде, он был слишком сложным языком для простых смертных где-то так в 1990-м году уж точно.

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

А именно, формула такая: простой интуитивный API, предсказуемое и прозрачное использование памяти и копирование объектов; а если для воплощения всего этого нужна продвинутая магия, пользователю не нужно о ней знать. Магия остается спрятанной в исходниках библиотеки.

Это было верно в отношении std::string, std::vector и std::pair еще в 90-х. Для того, чтобы их написать, включая удобные методы их использования, нужно было знать много трюков и хитрых углов стандарта. Для того, чтобы использовать, нужно было просто интуитивно представлять строку как объект, сам хранящий память и расширяющий ее по мере надобности, вектор как очевидный аналог массива объектов итд.

Это остается верным в отношении std::unique_ptr и std::optional сегодня. Если читать их исходники, то можно ошибиться и на секунду подумать, что забрел в какой-то проект на Скале. Зато использование вполне интуитивно.

std::variant немного выбивается из этого паттерна, особенно в том, что касается проблемы "посещения всех альтернатив", и близок скорее к философии Boost - откуда он и взят почти без изменений, собственно. То, что C++{11,14,17} в целом сопротивлялись Boost-ификации языка и выносу продвинутой магии на поверхность, там, где программистам нужно постоянно с ней сталкиваться - одна из причин успеха современного C++.

Не верите мне? Спросите Джона Кармака:


СсылкаОтветить

Comments:
From: (Anonymous)
2017-09-16 05:32 pm
Да. Надо сначала формулировать, а затем шпицрутенами поддерживать дисциплину программирования. А когда надо, чтоб Curiosity долетела и села, переходить на Си.
(Ответить) (Thread)
[User Picture]From: spamsink
2017-09-16 05:55 pm
и сказать по правде, он был слишком сложным языком для простых смертных где-то так в 1990-м году уж точно

По-видимому, потому, что он практически изначально был двумя языками в одном - языком прикладного программирования и языком программирования прикладных интерфейсов.
С появлением templates и развитием их возможностей к ним добавился язык мета-программирования, и все три объединены общим парсером и необходимостью поддерживать совместимость с Си. Так что, безусловно, выбор относительно вменяемого подмножества для каждой из подзадач программирования и удерживание в их рамках - единственный разумный подход.

Но синтаксическое безумие, к которому приходится прибегать при метапрограммировании, начинает утомлять.
(Ответить) (Thread)
[User Picture]From: livelight
2017-09-16 07:06 pm
Вы забыли посчитать язык препроцессора :)
(Ответить) (Parent) (Thread)
[User Picture]From: spamsink
2017-09-16 07:19 pm
Действительно, теперь надо и его считать, раз уже и он объединён общим парсером.
(Ответить) (Parent) (Thread)
[User Picture]From: winpooh
2017-09-18 03:50 pm
"C++ as better C" - самое замечательное подмножество C++. В рамках 98-го стандарта. Без template metaprogramming и множественного наследования.
(Ответить) (Parent) (Thread)
From: (Anonymous)
2017-09-16 05:58 pm
Делов-то. Кто-нибудь напишет правильный overload, выложит на гитхаб, и все станут пользоваться.
(Ответить) (Thread)
[User Picture]From: livelight
2017-09-16 07:05 pm
Имхо, насчёт слишкомсложности в 1998 году вы преувеличиваете - если "простым смертным" считать того, кто как-то освоил язык просто-Си. А если "простым смертным" считать пррлетария, не знающего, с какого бока подходить к просто-Си, и не способного его освоить без кровавых мозолей на мозге, то для него и просто-Си имени К & Р слишком сложен, по определению.
(Ответить) (Thread)
[User Picture]From: spamsink
2017-09-16 07:21 pm
Насколько я помню, виртуальное множественное наследование некоторым освоившим просто Си казалось слишком сложным с самого начала.
(Ответить) (Parent) (Thread)
From: (Anonymous)
2017-09-16 08:10 pm
Оно слишком хрупкое. Его нельзя делегировать, например.

captcha: avenida heritage ;)
(Ответить) (Parent) (Thread)
[User Picture]From: mtyukanov
2017-09-17 06:18 am
Оно было слишком ненужным, пока не нашлось применение в виде интерфейсов. Его использование до того практически всегда означало плохой дизайн. Из-за ненужности и сложность -- запоминать то, что применяешь раз в несколько лет... Лонгджампы сишные в сегментных моделях тоже были непросты, но ими пользовались постоянно.
(Ответить) (Parent) (Thread)
[User Picture]From: fima
2017-09-16 07:53 pm
Я вот использую std::variant и никаких проблем с написанием визиторов не испытываю. Гораздо больше раздражает невозможность в дебаггере, по крайней мере, в lldb, посмотреть какой же вариант сейчас сидит в переменной. Но это проблема дебаггера, надеюсь, рано или поздно это нормализуется.
(Ответить) (Thread)
From: (Anonymous)
2017-09-16 08:08 pm
gdb прекрасно показывает
(Ответить) (Parent) (Thread)
From: (Anonymous)
2017-09-16 08:06 pm
>он был слишком сложным языком для простых смертных где-то так в 1990-м году уж точно.

Он был слишком простой в 1990. Недостаточно поддержанным.
(Ответить) (Thread)
From: vfork
2017-09-17 08:34 am
QVariant решает эти вопросы почти идеально. А поскольку он не наследует от QObject, то этот подход может быть использован и вне Qt
(Ответить) (Thread)
[User Picture]From: migmit.dreamwidth.org
2017-09-17 09:32 am
С плюсами у меня примерно как с эрэфией: если и подумаешь иногда «а может, можно будет и вернуться как-нибудь?», то достаточно прочитать какую-нибудь новость из этого мира, и дурь проходит.
(Ответить) (Thread)
From: (Anonymous)
2017-09-17 02:31 pm

Брррр

си++ избыточно сложен, отвратителен и нелеп ибо был зачат в суете, молодым глупым программером, только и думавшим как бы в него побольше фич завернуть. Синтаксис поганый. Множественное наследование уродливо и запутано. Модификаторы доступа конечно еще больше огня поддают, на пару с генериками. Референсы, френдшип и консты как-то сделаны по-дурацки - намерение благое, но исполнение дурное. Чтобы реализовать тривиальную для жавы делегацию, надо целый концерт с бубном устраивать.

Вместо того, чтоб поддерживать этого франкенштейна и "развивать", следовало бы бросить усилия на тот же раст или смолток, или аду, или даже паскаль - пользы было б в разы больше.
(Ответить) (Thread)
[User Picture]From: Daria Klukin
2017-09-17 02:59 pm
Когда о проблемах с++ говорят на примерах подобно этому это похоже на критику русского алфавита неспособного правильно передать звук другого языка.

Ужасно конечно выглядит эта попытка, и это действительно проблема но не языка а самой комити - очень уж много куда лезла и улучшала (на мой взгляд простого юзера) и считала что си должен мочь все и для всех. Но вроде как остановились теперь.
(Ответить) (Thread)
[User Picture]From: gul_kiev
2017-09-18 05:48 am
Мне кажется, что программисту полезно понимать, что и как происходит "под капотом". Это позволит обходить грабли и выбирать более эффективные решения. "Оно работает на какой-то магии" - это подход гуманитария, а программисты - инженеры.

Конечно, если у РК86 можно было полностью дизассемблировать и прочитать monitor, у msdos знать таблицу функций 21-го прерывания, то потом всё знать уже стало невозможно, приходится полагаться на то, что всякие библиотеки и фреймворки работают в соответствии с документацией. Тем не менее, мне кажется, что хороший программист при написании кода хотя бы в общих чертах представляет себе, что получится в результате компиляции. Правильно ли ориентироваться на то, что программист этого всё равно не представляет, и скрывать всю магию внутри библиотек - не знаю, не уверен.
(Ответить) (Thread)
From: (Anonymous)
2017-09-18 06:07 am

Нереально же

В проектах сложнее чем хелловорлд хотя бы на 3 порядка приходится использовать такое количество библиотек, что отдельному программеру просто невозможно знать детали реализации каждой. Приходится именно полагаться на порядочность и компетентность незнакомых разработчиков либо изобретать велосипеды. Конечно базу нужно понимать - например, что каждый новый тред приносит с собой ненулевой размер стека, что переключение контекстов не происходит бесплатно и тому подобное. Но все тонкости? Увольте.
(Ответить) (Parent) (Thread)
[User Picture]From: livelight
2017-09-19 12:58 pm
> всякие библиотеки и фреймворки работают в соответствии с документацией

Дык, в посте про то и говорится, что некоторые библиотеки невозможно использовать, не залезая в аццкие глубины буста, в терминах которых эта документация вынужденно сформулирована.
(Ответить) (Parent) (Thread)
From: luarvique
2017-09-18 03:14 pm
"C++ to C is what lung cancer is to lungs."
(Ответить) (Thread)
[User Picture]From: loyso_b
2017-09-23 07:50 am
Эх - типичные проблемы general purpose languages. Как всем быть счастливыми с единственным компромиссным API на всех.
(Ответить) (Thread)