Комментарии 276
Как язык C++ довольно ужасен и неоднозначен. И с точки зрения концепций, и с точки зрения синтаксиса, и с точки зрения инфраструктуры.
Новые стандарты его, к сожалению, особо лучше не делают. Нет, конечно, и хорошие вещи приходят, но часто это "OMG WTF"?
Но это практически единственный ОО-язык высокого уровня, на котором можно напрямую общаться с железом, писать сервера, игры, да и вообще всё подряд, используя ресурсы машины по максимуму. Так что хоронить дедушку рано.
Какие конкретно концепции С++ вам не нравятся? Время показывает, что они крайне хороши.
Претензия по синтаксису тоже непонятна
> Но это практически единственный ОО-язык высокого уровня,
С++ это не ооп язык
С++ это не ооп язык
Мультипарадигменный, как и большинство современных языков. Да, в идиоматическом C++ писать в чисто ООП стиле не принято и не особо-то эффективно, но формально C++ вполне себе ООП, равно как и процедурный, структурный, функциональный язык.
Так пишите код, в котором нет UB. Оно проявляется в таких конструкциях, за которые и так бы по рукам надавали.
Когда я с 0 учил язык, он выглядел просто как очередной язык программирования, просто с более строгой структурой описания алгоритмов. Но когда в конце циклов статей осталась последняя глава "шаблоны и STL"... Я перестал мыслить как нормальный человек. Ты буквально делаешь компилятор в компиляторе, где остановит тебя только фантазия, а твой код всегда заботливо оптимизирует компилятор))
Ps Делал свойства как в С#. Делал запись типа int x = classT.at[4] валидной, где classT { void* ptr; };
А потом в "твоих" фантазиях должен сидеть и разбираться другой человек, потому, что ты заболел/уволился/повысился и т.д.
Так и рождается код о котором говорят "работает вот и не трогай", т.к. в нём никто не может разобраться и контакта с автором больше нету, а на код завязано, что ни будь важное и тестов никто не написал. Никто его ни отрефакторить не может ни подправить, в некоторых случаях даже компилятор обновлять может быть страшно, так все и живут с этим "фантастическим" куском ... кода годами и десятилетиями без возможности сделать шаг влево/вправо.
При всем уважении к C++ и моему опыту на нем - не надо писать на нем вообще ничего сейчас, кроме очень-очень редких вещей, типа виндовых кернел драйверов (никсовые на расте уже можно).
Отсутствие кучи всего из коробки, боль с депендами даже при использовании депенденс менеджера, сложность отладки, УБ, зоопарк из систем сборки, где нормальная ровно одна (нет, не CMake) и прочее - вы поняли.
Вместо срача - просто рекомендую попробовать современный C#. Вот уж где реально универсален, кроссплатформен, есть ВСЕ, быстрый, депенденс менеджер нормальный и встроенный. одна система сборки человеческая, работающая везде.
Вот таким должен быть язык, а не ифдефы, симейк, управление памятью и прочие ужасы.
Не хватает только нормальной кроссплатформенной оконной библиотеки.
Если говорить про "лучший" C++, то это будет не C#, а Rust. Там по-человечески сделана система управления ресурсами/lifetimes - исправлено то, за что справедливо критикуют C++ в области работы с памятью. При этом отсутствуют ужасы null-values и есть явное разделение ссылочной и by-value семантики
Если бы ещё синтаксис расту разрабатывали без цели увеличения дохода офтальмологов...
Написав на Rust относительно немного кода, после лет в С++, не вижу проблем в его синтаксисе вообще, особенно по сравнению с С++.
Разве что то, что он пошёл не только от С, как в PHP или Javascript.
Другими словами, да, программист на С++ может выучить PHP за выходные, а Rust не может. Но это не проблема Rust, а следствие из более продвинутых фич, которых в С++ не существует: expression syntax, rich enums, borrow checker, и что там ещё.
Каждый раз, когда кто-то в очередной раз ругает синтаксис Rust, я предлагаю указать, что именно с синтаксисом не так. Где-то 90% отваливаются на этом вопросе, а те, что таки отвечают по существу, в итоге предлагают что-то значительно хуже.
Ну вот берём прям первое, что видит программист, заинтересовавшийся растом:
println!("Hello World!");
Почему посреди фразы здесь знак "!"? Как мне прочитать это вслух? Люди привыкли к синтаксису английского языка, практически все языки программирования пытаются так или иначе к нему приблизиться.
Ок, берём задачку чуть сложнее: посчитать количество символов "_" и "-" в строке.
Код из cargo, каноничнее некуда:
impl<'s> UncanonicalizedIter<'s> {
fn new(input: &'s str) -> Self {
let n = input.chars().filter(|&c| c == '_' || c == '-').count() as u32;
Что означает весь этот мусор? <'s>, |&c| c - зачем всё это? Как это прочитать вслух?
Я понимаю, что можно быстро привыкнуть и всё такое... но вот у многих это нелюбовь с первого взгляда. Не прёт язык и всё тут.
Т.е. это вслух читается на ура? А знаки "меньше" странно сгруппированные по двое ну вот совсем никого не смущают.
std::cout << "Hello world!" << std::endl;
std::map
, std::string
, std::vector
,std::cout
, std::endl
,…
Ужас. Зачем тут постоянно повторяется std::
, зачем этот мусор?
Потому что руко**опы из комитета не смогли сделать нормальный using namespace. Теперь везде этот std::мусор.
Впрочем, если вы точно знаете что делаете, вы всё ещё можете написать using namespace std;
, и тогда всё будет вполне понятно и красиво:
cout << "Hello, world!" << endl;
Потому что руко**опы из комитета не смогли сделать нормальный using namespace.
Да потому что невозможно похоронить тянущееся с 60-х годов прошлого века наследие в виде include-файлов и препроцессора.
Впрочем, если вы точно знаете что делаете, вы всё ещё можете написать using namespace std;
Как альтернативу, комитет предложил модули, где каждый файл — отдельный translation unit, и где вы вполне можете делать подобные вещи.
И что мешало в том девяносто лохматом году, когда вводили namespace
, объявить, что теперь каждый неймспейс компилится как независимая либа и подключается как либа? Тулинг это поддерживал и тогда, просто это требовало дополнительных приседаний по настройке сборки, а программистам, как обычно, лень.
Времена, когда язык программирования выглядел как текст на английском (COBOL), уже давно прошли. Это слишком многословно и все равно вынуждает учить синтаксис язык программирования.
Ваша претензия заключается только в том, что вы привыкли к C-подобному синтаксису, характерному для большинства мейнстримных языков, и просто отказываетесь принимать всё остальное.
Я, например, до Си - подобного синтаксиса познал синтаксис Pascal/ADA и переход на С++ мне казался адом, до некоторого момента. Раст мне нравится, его концепция, философия и даже синтаксис местами. Но почему код на Хаскеле кажется более читаемым? И это не только мое мнение. Ведь человек, который легко читает код на Хаскеле, наверняка осилит и любой другой, но это не работает с Раст почему-то.
А зачем это читать вслух?
Почему посреди фразы здесь знак "!"?
То, что это макрос объясняется в первой же главе книги по языку. Ну да, с какой-то теорией придётся ознакомится, иначе, в зависимости от предыдущего опыта, можно очень до многого докопаться. Например, зачем в С++ нужно ->
? Вон в С# всё через точку. Если что, не надо мне объяснять, а на С++ много писал, это просто пример.
Ок, берём задачку чуть сложнее: посчитать количество символов "_" и "-" в строке.
К "задаче" относится только часть приведённого фрагмента кода, поэтому можно упростить до input.chars().filter(|&c| c == '_' || c == '-').count()
. Ну или, по крайней мере, до вот такой функции:
fn num_chars(input: &str) -> usize {
input.chars().filter(|&c| c == '_' || c == '-').count()
}
Не всё так страшно, не правда ли? Кажется, остаётся только претензия к |&c|
. Если амперсанд забыть, то компилятор точно скажет, что не так, ну а различать значения и ссылка вполне нормально для системного языка. Ну и наконец синтаксис лямбд в С++ тоже достаточно страшный/перегруженный и ничего.
Да всё понятно. Меня просили объяснить, что не так с синтаксисом раста - я объясняю. Когда первый раз открываешь код на расте, возникает ощущение, что у кого-то по клавиатуре прошёл кот и нажал рандомные кнопки, включая хоткеи с автокомплитом.
Вы не поверите, но точно такое же ощущение у меня возникает, если взглянуть на текст на китайском, японском или корейском
Меня просили объяснить, что не так с синтаксисом раста — я объясняю. Когда первый раз открываешь код на расте, возникает ощущение, что у кого-то по клавиатуре прошёл кот и нажал рандомные кнопки, включая хоткеи с автокомплитом.
Всё-таки не могу согласиться. Мне кажется, что такое мнение может сложится разве что у человека, который кое-как освоил один язык. Вероятно, динамический — там код обычно действительно проще выглядит. А если осмотреться по сторонам, то начинаешь гораздо спокойнее к этому относиться. Я вот сложные LINQ выражения с трудом читаю, но C# разработчики, вроде как, весьма довольны этим инструментом. В скале разрешено вводить произвольные операторы, и как-то живут же. И это я ещё не говорю про лисп или хаскель.
У меня вот в прошлом основным языком был С++ и поэтому совсем не могу понять нападок на синтаксис раста. А ведь таковые нападки и от плюсовиков нередко раздаются. Согласиться могу разве что с претензиями к макросам (которые macro_rules). Мне вот приходится каждый раз разбираться, когда возникает необходимость написать макрос. Правда бывает это не то чтобы сильно часто, может поэтому они и забываются каждый раз.
Скала имхо - это почти вершина сложности синтаксиса. Как по мне, код на ML-подобных языках читается гораздо проще.
Что касается раста - там есть несколько шероховстостей, но чувствуется, что ребята очень щепетильно относятся к синтаксису и хорошо поработали. macro_rules!, кстати, тоже неплохи. Просто это другой язык, который редко используется.
Мне кажется, что рассказы про вырвиглазность раста, надуманные проблемы с unsafe и прочее - это просто проявление парадокса блаба. Разве что, вместо unsafe можно было бы выбрать более точное слово и &mut заменить на какой-нибудь &uniqe.
Попробуйте вслух и с выражением прочитать C++ версию. Не вижу особенной разницы.
UncanonicalizedIter::UncanonicalizedIter(std::string_view input) {
uint32_t n = input
| views::filter([](auto c) { return c == '_' || c == '-'; })
| ranges::size();
судя по "null-values" вы совершенно не знаете ни раст, ни С++.
Раст это язык, который дизайнили для отсутствия сегфолтов(спойлер - не вышло, см. unsafe который ВЕЗДЕ).
С++ дизайнили для качества получаемого кода: инкапсуляции сложности в больших системах, масштабирования.
Что уж говорить, если весь синтаксис раста заточен чтобы его легче было парсить(КОМПИЛЯТОРУ!), а не человеку(а нейминг просто -10 из 10)
Вот вы похоже Rust не знаете. Там unsafe не такой как C++ - то есть совсем. И дает кучу гарантий. А с синтаксисом. Просто он не сишный в своей основе - а парсить современные плюсы человеку вообще невозможно - одни темплейты вышибают напрочь на часы.
У меня отлично получается парсить шаблоны, никаких проблем.
А unsafe в расте, да, даёт кучу гарантий. Неявных гарантий которые вы обязаны соблюдать, иначе УБ.
Требований к unsafe коду в расте БОЛЬШЕ чем к коду С++ и требования не такие очевидные, как не обращаться к невыделенной памяти. Например создание ещё одной ссылки на то на что уже есть ссылка это уже уб
P.S. то что вам сложно парсить в С++ просто невыразимо в расте, т.к. там нет многих возможностей шаблонов и совсем нет вариадиков.
Смешно, в языке где в синтаксисе есть туплы количество типов в тупле ограничено!
P.P.S. если вы попробуете распарсить растовый макрос, то окажется что он значительно сложнее любого шаблона. Имеет синтаксис который вовсе зависит от левой пятки программиста его писавшего.(а макросы там буквально ВЕЗДЕ, например нет способа создать вектор без макроса)
например нет способа создать вектор без макроса
Создал: Vec::new()
. Сейчас будет уточнение, что надо создать вектор с элементами?.. Ну ладно: Vec::from([1, 2, 3])
.
Вау, только вот это пожалуй самые непопулярные конструкторы вектора.
Там штук 10 макросов для его создания и среди них нет возможности создать с кастомным аллокатором, собственно поддержка аллокаторов в расте это плевок какой-то, она лишь на бумаге
К слову, о читаемости раст макросов:
![](https://habrastorage.org/getpro/habr/upload_files/390/3bd/41a/3903bd41af2ac5cf1fa61d583607b0d5.png)
Вообще язык декларативных макросов в Rust очень простой. Но от символов в глазах рябит, это правда. Сделано как проще, чтобы меньше было пересечений в обозначениях макрокоманд с остальным кодом на Rust, так как они смешиваются в макросе.
Да в чем проблема символов? Тут все так пишут словно это уже устоявшийся факт что много разных символов это плохо. Я наоборот терпеть не могу языки типа lua потому что их сложнее парсить визуально большими кусками, так как все сливается в одно оргомное сочинение. И тот же знак '!', для макросов был бы отличной штукой в C++ по которому даже без подсветки было бы легко понять что это за конструкция.
У меня отлично получается парсить шаблоны макросы, никаких проблем. (спасибо за аргумент)
Даже со старта с этим не было проблем. Если быть немного знакомым с синтаксисом старых скриптовых языков, шелла, например, где переменные и выражения берутся в ${}
и $()
, то вообще читается без запинки.
у шаблонов такой же синтаксис как у обычного кода, у макросов - нет
читается без запинки.
в этом чтении нет никакой информации о том какой тип ожидается, тогда как в аналогичном конструкторе std::vector из С++ чётко написано, что это size_type или что-то такое
у шаблонов такой же синтаксис как у обычного кода, у макросов - нет
Пусть бросит камень тот, кто совсем-совсем не использует препроцессор. Ни в новом коде, ни в том, который просто приходится читать.
в этом чтении нет никакой информации о том какой тип ожидается, тогда как в аналогичном конструкторе std::vector из С++ чётко написано, что это size_type или что-то такое
Ну, я бы не сказал, что вот это: https://doc.rust-lang.org/src/alloc/macros.rs.html#63 намного хуже, чем вот это: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_vector.h#L84. Да, я помню, кастомные аллокаторы.
И да, макросы могут не давать возможности сразу прочитать типы в сигнатуре. По этому критерию, специально сконструированному так, чтобы отсечь Rust, признаю, Rust проиграет. Хотя лисперы ещё поспорят.
Правда, выиграет сразу на следующем шаге, при проверке типов при компиляции, и диагностике. Мой С++ заржавел, я ещё помню сотни строк ошибок в загадочных местах при простой опечатке в тексте - этого в современном С++ уже совсем-совсем нет?
Препроцессор С ничего общего с синтаксическими макросами раста не имеет. И присутствует он там т.к. это библиотека сразу на все версии С++ начиная с незапамятных времён(а нейминг переменных специально таков, чтобы не пересекаться с именами из кода пользователей, что кстати уже не нужно начиная с С++20 модулей)
В остальном там обыкновенный код с таким же синтаксисом как в любой другой части С++.
Чтобы писать на С++ необязательно использовать макросы, в расте без них и строки написать невозможно.
А какие ошибки будут при опечатке в макросе - ну посмотрите, проверьте.
Ну вот я посмотрел, проверил: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=93eff61c9e43b0c207a7cf05c825ee27
Вроде ничего сложного в этих ошибках.
Хотя, честности ради: процедурные макросы я ещё не осилил, и да, они гораздо сложнее, и завязаны на API AST. Впрочем, я слышал, что старые лисперы ими крайне довольны.
судя по "null-values" вы совершенно не знаете ни раст, ни С++.
Ярлыки навешивать вы умеете. А по существу скажете какие есть ужасы null-values в rust/С++? Система типов там достаточно мощная, чтобы явно выразить, что значение может или не может отсутствовать
В современном мире предлагать вендорлокнутый язык, который уж точно проигрывает плюсам в скорости...
Это только для прикладных программистов есть выбор между C/C++ и C#
Для системных программистов, разработчиков встраиваемых систем собственно и выбора никакого нет.
С# никогда не сравнится по производительности с нативным компилятором.
https://habr.com/ru/post/266163/
Да и по переносимости/тиражируемости кода тоже.
Ссылке 7 лет. Вы бы еще .net 1.0 откопали.
Конечно задачи где разница в производительности очевидна найти можно, но таких довольно мало.
По переносимости как раз ровно наоборот, c++ требуется компилировать под каждую платформу с кучей #ifdef, имея на выходе 100500 разных бинарников зачастую с зависимостями от разных библиотек. Причем с кросс-компиляцией все очень плохо - собрать на винде приложение например под мак в большинстве случаев ни разу не получится и наоборот. Тогда как должным образом написанное .net приложение просто запускается на любой операционке как есть.
Как можно сравнивать C++ и C#? Совершенно разные задачи решают. С# забудут, C/C++ останется, потому что всё также надо будет писать компиляторы, игровые движки, игрушки консолей - с выдавливанием всех возможностей железа, драйвера, прошивки контроллеров и встраиваемых устройств, встраиваемые модулии в критические места приложений на других, более высокоуровневых языках (тот же C#). Например в тот же фронтенд: https://developer.mozilla.org/ru/docs/WebAssembly/C_to_wasm
Можете возразить, что игры и на C# пишут, на Unity, к которому куча модулей на C#. Ок, но runtime Unity опять же C++.
Можете возразить, что игры и на C# пишут, на Unity, к которому куча модулей на C#. Ок, но runtime Unity опять же C++.
Рантайм C# тоже на C/C++ написан. Не вижу здесь никаких проблем.
Совершенно разные задачи решают.
Вот именно. Просто надо понимать, что нет языка, который был бы хорош абсолютно везде. Поэтому хорошим решением в больших проектах будет не жрать кактус и не писать всё на C++, равно как и не писать всё на C#, а использовать сразу несколько языков.
и чего же такого ужасного в llvm? даже ghc через него может работать
А компилятор С++ должен быть написан на C++, потому что компилятор языка Х всегда написан на Х (сарказм)
Сможете назвать что в LLVM сделано не правильно потому что С++ не такой как надо ?
Сможете назвать что в LLVM сделано не правильно потому что С++ не такой как надо ?
Эмуляция сумм-типов через наследование.
В принципе я соглашусь что сумм-тип через наследование это извращение, но если и кто-то практикует это извращение то не из за того что это ограничение языка.
Но у меня вопрос где вы это нашли? Я знаю там только https://llvm.org/doxygen/PointerSumType_8h_source.html
но он не реализован через наследование.
В принципе я соглашусь что сумм-тип через наследование это извращение, но если и кто-то практикует это извращение то не из за того что это ограничение языка.
Это именно что ограничение языка. В clang используют наследование для типов узлов в AST. В GCC используют… Ну, не наследование, но его эмуляцию, указатель на структуры разных типов с общим префиксом, которые в рантайме различаются по уникальным номерам.
std::variant
появился только в C++17, и пользоваться им неудобно.
Это все конечно верно, но читаемый код на С++ это довольно большая редкость, потому если только все вышеперечисленное не требуется в проекте одновременно, то если отбросить религию будет логичнее выбирать более удобные и более дешевые в поддержке варианты.
работало в 2000-м — заработает и сейчас
…если было написано в соответствии со стандартом. А это, скорее всего, не так.
Не, ну если найти компилятор из 2000 года - то заработает.
Впрочем, с остальными языками та же фигня.
Мало найти компилятор. Надо ещё и древние зависимости откопать, ведь компилятор 2000 года не сможет скопилировать современный код. А потом окажется, что древние зависимости работают только со старыми либами, которые уже не работают в современной операционной системе. Или или сам компилятор запустить не получится.
всё будет работать, даже если там было дикое уб достаточно будет компилировать без оптимизаций
дружит со всеми БД
простите, взоржал :) Возможность слинковаться с сишной либой (и потом работать в стиле С, как хочешь так и приседай) не есть "дружит". Все остальные языки, вы не поверите, тоже под капотом линкуются с сишными либами всех БД, только они ещё мапят SQL-типы данных в свои нативные.
std::variant нужно было завозить в 1990, а не в 2020
ну, нет много миддлов уже на С++. для меня всегда был затык в том, чтобы взять проект на плюсах: хрен найдешь разработчиков, причем, любого уровня.
Kotlin, where are you?
https://kotlinlang.org/docs/multiplatform-dsl-reference.html#targets
Плюс compose для мультиплатформы тоже пилится
по большей части плюсану)
но вот
есть ВСЕ, не из коробки, да, но есть
Это "все" часто вырвиглазно, нередко с сишным интерфейсом, в абсолютно разных coding-style'ах, без нормального репозитория, часто хочется плеваться.
универсален, кроссплатформ
Только пересобирать каждый раз надо под каждую платформу. А если платформ >2, то уже проблемы.
Дополню:
Геморой с зависимостями. Авторы либы X сломали бинарную совместимость, а рассказать об этом забыли? welcome to hell. Java аккуратненько вальнется с исключением, по которому тут же, сразу же все будет понятно, в случае плюсов получите segfault хз пойми где. Надежно выручает только докер.
Но все же, в плюсах мне всегда нравился STL, он зачастую удобнее джавовых и скаловых коллекций. Задачи на том же литкоде до сих пор на плюсах решаю. Boost, я тут недавно глянул, за 6 лет, что я на плюсах не пишу, распух раза в полтора.
Проблемы начинаются когда мы пытаемся на с++ работать с вебом. Где websockets, socket.io, где нормальная работа с базами, удобная работа с json ? Все это делается через ужасные либы, и жутко не удобно.
В остальным С++ хорош конечно, но только если вы держите его далеко от веба.
Практически всё что вы перечислили - это просто результат того что 30 лет не было достойных альтернатив, а задачи нужно было решать. Конечно за столько времени чего только не напишут.
C++ прост, как 3 копейки? Это была шутка? Почитайте С++ language reference, это самое толстое описание языка, какое я знаю. И конечно, убивают многочисленные undefined behavior.
Насчет стандартов, в большей части корпоративного рынка используются крайне устаревшие версии языка (аналогично с Java) и даже переход на следующую менее устаревшую версию это очень ресурсноемкая процедура.
Очень, очень долгая компиляция и линковка, даже с precompiled headers, которые сам же Microsoft иногда просит отключать в сложных случаях (не надо вспоминать про incremental, кроме сборки на личном компе она мало где используется).
Кроссплатформенность отсутствует из коробки - базовые численные типы зависят от платформы.
Но и никто не спорит, что во многих нишах это по-прежнему почти единственный приемлемый выбор языка. ;)
Все остальное лучше писать на других языках, если это не махровое легаси.
Ну ок, мб эмбед, я от него далеко.
> вы троллите? (глянул Ваш профиль)
Нет. Я правда так считаю. Медовый месяц с языком спустя несколько лет перетек во всё большее раздражение от его использования.
А потом я познакомился с шарпом, и увидел, как можно писать код без запоминания кучи правил, без страданий с кросскомпиляцией, без борьбы с симейком, где из коробки (в нугете) есть вообще все, без мейнтенанса своего миррора с зависимостями, без кучи бойлерплейта (а-ля енум-ту-стринг или парсинг джсонов)
Заканчивая такими приятными мелочами, как компиляция за секунду для быстрых итераций разработки (и нативная компиляция для прода на CI в .net 7), сплит строки из коробки и прочие очень приятные мелочи, которые снова позволяют получать удовольствие от программирования.
Ну и сишное OS-апи все еще дергается без проблем, чуть-чуть сложнее, чем в крестах, но это та цена, на которую я готов.
По сути, у C++ есть реально только два основных плюса: производительность скомпилированного приложения и непосредственный доступ к железу.
Мы используем С++ ровно из-за этих причин. Наши приложения должны работать в RealTime и постоянно общаться с внешними устройствами.
Системы сборки и зависимости библиотек и инклудов - это ад. Проблема с зависимостями более-менее решена в Linux, но почти никак в Windows. Из-за этого приходится в свои танцы с бубном.
Хорошо, что есть Qt на свете - по крайней мере, многие проблемы переносимости она решает (но не все).
где нормальная ровно одна
Посоветуете?
где нормальная ровно одна (нет, не CMake)
это вы про кого?
Но работа с изображениями — далеко не единственная область, в которой доминирует C++. С большой долей вероятности браузер, который вы используете для чтения этой статьи, также был написан на C++, как, например, Chrome и Firefox.
А разве Firefox не был переписан на Rust?
Нет, servo так и не взлетел и остался экспериментальным движком, а затем растаманы были уволены из умирающей Mozilla в большинстве своём. Сейчас судя по истории коммитов servo пилится парой человек с большими перерывами - месяцами там вообще не бывает коммитов за исключением автокоммитов от dependabot'а.
Мое личное мнение: Servo утонул под тяжестью растового легаси. Он активно писался ещё во времена не очень стабильного Rust, когда и экосистема была не развита, и практик не было выработано. Собственно, благодаря Servo (в том числе) это со временем устаканилось. Servo выполнил свою функцию. Даже удивительно, что кое-что попало из него в Firefox. В настоящей момент в Servo невозможно контрибьютить - нужно переписывать заново.
Только маленькие части где это действительно нужно было.
Интеллектуальная небрежность
Как поделился со мной в Твиттере Марек Краевски (Marek Krajewski), некоторые люди просто не стали бы использовать C++ из-за интеллектуальной инертности.
Так небрежность или инертность?
Прям по Фрейду...
Приведенные выше цифры впечатляют.
Да я аж офигел, когда увидел, что TypeScript в 5 раз медленнее интерпретирует (?) тот же самый JS код на той же самой VM. Это ж как нагло надо врать статистикой, чтобы миллиону разработчиков говорить такое в лицо?
Да, цифры этой статистики крайне тупые(сделаны фанатами раста, судя по цифрам).
Сделать чтобы С++ был в 1.6 раза медленнее С, при том что в нём компилируется ТОТ ЖЕ код это нереально тупо конечно
Ну почему же, С++ это еще и CRT.
Зачем вы общаетесь магическими словами? Вы можете раскрыть мысль? С++ быстрее С за счёт больших требований и возможности писать генерализованный нормальный код с теми же стл алгоритмами. В С ради этого вам придётся писать под каждую мелкую задачу дико оптимизированный код, что просто невозможно физически
Ок, обьясню проще. В С++ присутствуют накладные расходы на выполнение под капотом CRT. В чистом С можно писать код без этого, наиболее приближенный к платформе, стало быть, более эффективный и производительный. Не зря ядра ОС и большинство системных библиотек пишутся на С.
1) CRT - это C runtime library, оно как раз для C.
2) код, написанный на C, обычно без особого геморроя можно скомпилировать C++ компилятором. Вы утверждаете, что код, скомпиленный компилятором C, выполняется быстрее, чем тот же код, скомпиленный компилятором C++?
3) В windows ядро в основном написано на C++. Если говорить про *nix, то системные библиотеки пишут на C потому, что а) у него более стабильный ABI и б) их начали писать 40 лет назад - традиция-с.
Если говорить про *nix, то системные библиотеки пишут на C потому, что а) у него более стабильный ABI и б) их начали писать 40 лет назад — традиция-с.
Добавлю ещё и тот факт, что компилятор C есть в каждом утюге, тогда как компилятора C++ под целевую платформу может попросту не существовать. Язык C даёт оптимальный баланс между уровнем абстракций и охватом различных платформ.
Вы утверждаете, что код, скомпиленный компилятором C, выполняется быстрее, чем тот же код, скомпиленный компилятором C++?
Нет, я утверждаю, что С++ код с классами и сопутствующими конструкторам\деструкторами и таблицами методов\свойств не может быть быстрее, чем без всего этого.
а если конструктор/деструктор без кода? я не тролю, не смотрел дизассемблер, но предполагаю что затраты около нуля. А если в конструкторе/деструкторе чтото есть, то наверно по логике и в подобном Си коде будет иницилизация/освобождение?
Там хватает неочевидных моментов. Тот же std::vector<int> например всегда будет zero-initialized если ему сделать .resize() что не очень осмысленно если он потом заполняется данными. Особенно это доставляет когда std::vector<char> используется просто как низкоуровневый буфер для сериализуемых данных, поскольку он тогда не просто инициализируется нулями, но еще и делает это побайтово (я смотрел ассемблер, выясняя чего оно тормозит, да). Это можно исправить, но это скажем так не очень очевидно и просто делается.
А вот это могут и пофиксить.
Таблицы свойств в С++? Хм...
Тривиальные конструкторы и деструкторы в плюсах отлично инлайнятся. С другой стороны, нетривиальные конструкторы/деструкторы есть и в С, просто они называются blabla-open или *-init, и вместо new/delete вам надо залезть в документацию и выяснить название соответствующего метода.
Открою страшную тайну, но ядро линукса написано на Си, но с использованием олдскульного ООП. Примерно все драйверы и модули представлены в рантайме объектами известной структуры, которые реализуют необходимые интерфейсы при помощи таблиц указателей на функции с известной сигнатурой.
Таблицы виртуальных методов могут быть и быстрее, чем сишный switch, который компилится в кучу условных переходов. Это зависит от конкретной ситуации, ну и как бы в школе рассказывают, что "не плоди виртуальных методов без реальной надобности".
Открою страшную тайну, но ядро линукса написано на Си, но с использованием олдскульного ООП
Это как это чистый Си поддерживает ООП??? Это получается чистый Си это ООП язык?
Как же вас тут ООП специалисты не забодали еще :) ?
C++ код с классами, конструкторами и деструкторами будет столь же быстрым, как и аналогичный ему C код, но будет более коротким (если код написан правильно, с обработкой ошибок) и читабельным - это если не пользоваться идиоматическими C++ возможностями, а именно виртуальными функциями и исключениями (отключить вообще исключения опциями компилятора).
Если брать более идиоматический код и добавить виртуальные функции, то они будут либо чуть-чуть медленнее, чем применяемые в таких ситуациях C ссылки на функции (если ссылки лежат прямо в структуре - но тогда C-шный вариант будет более прожорлив по памяти), либо такими же по скорости (если C-шный вариант применяет эрзац таблицы виртуальных методов по типу struct ..._ops), либо даже чуть быстрее (32-битный Windows ABI - thiscall более оптимально использует регистры, чем cdecl)
Если добавить исключения как идиоматическую замену кодам ошибок, то код становится еще компактнее и быстрее в "обычном" случае безошибочной работы (т.к. большинство ABI обеспечивают бесплатный try/except, а в C требуется проверка кода ошибки везде). Исключение - тот же 32-битный Windows ABI, где try не бесплатен.
Во первых, все эти ексепшн ртти и шаред поинтеры если используются, то очевидно в С коде использовалось что-то чтобы их заменить.
Во вторых, там простейший код с каким то алгоритмом чего-то там считать.
Перечисленные вещи не медленные и не "жирные", это распространённое заблуждение, повлиять на перфоманс в плохую сторону могут разве что исключения при неправильном их использовании(в качестве логики, а не индикации исключительной ситуации) и rtti при постоянных динамик кастах - но это чудовищно плохой код
Зачем вам в строке COW вообще непонятно
одна JMP и одна MOV-инструкция
И как, хорошо JMP работает, если нужно перейти в неизвестный обработчик, который определён на десяток уровней вверх по стеку, и не забыть по дороге освободить ресурсы и память?
Если у вас обработчик вот здесь рядом, и к нему можно перейти через goto / if-ы, то вам и исключения не нужны. Собственно, в плюсах по этой причине и нет finally, чтобы не злоупотребляли исключениями в рамках одной функции.
Вы напишите goto с errno в какой-нибудь асинхронной функции, потом сравнивайте.
В плюсах есть finally. Деструктор называется. При большом желании можно даже передавать лямбду в конструктор класса finally, и вызывать её в деструкторе. Более того, деструкторами пользуется приблизительно каждый контейнер в стандартной библиотеке.
А так вы, конечно, правы, и я не понимаю, что вам тут доказать пытаются.
В плюсах есть finally
Нет. Это утверждение из серии про "дружит со всеми БД" выше.
В плюсах есть костыль для эмуляции finally. Иногда задача легко и красиво ложится на деструктор, особенно если вы заранее упоролись по RAII (это так же требует, чтобы подкапотный код, какие-нибудь сишные либы или интерфейсы, хорошо натягивались на идею RAII). Замечу, я не против RAII самого по себе, просто не всегда это оптимальное решение. А других по факту нет.
Бывают случаи, когда у ресурса больше двух состояний (он может быть не только открыт/закрыт), и вы не уничтожаете объект при ошибке, а переводите его в некое другое состояние. Бывает, что объект нельзя закрывать повторно - например, double free это UB. Наконец, чаще всего бывает, что у нас просто есть протокол, который требует после операции А обязательно сделать операцию В, не зависимо от успеха А, а А швыряется исключениями.
Во всех перечисленных случаях нам нужно либо копипастить, либо создавать аж целый класс ради вызова операции В в его деструкторе, либо колхозить флаги и if-ы c goto. Сравните с finally или, особенно, с Gо-шным defer. Язык должен помогать, а не заставлять учить паттерны ради паттернов.
Во всех перечисленных случаях нам нужно либо копипастить, либо создавать аж целый класс ради вызова операции В в его деструкторе, либо колхозить флаги и if-ы c goto. Сравните с finally или, особенно, с Gо-шным defer
Если вы после C++11 не можете сделать аналог Go-шного defer-а сами, то его можно взять, например, в GSL.
Язык должен помогать, а не заставлять учить паттерны ради паттернов.
Чтобы язык помогал, его нужно освоить. Хотя бы.
Если вы после C++11 не можете сделать аналог Go-шного defer-а сами, то его можно взять, например, в GSL.
Ну так а я о чём? 27 строк бойлерплейта, причём ну не джуниорского уровня (эксплисит конструкторы, удаление операторов по умолчанию, не самая простая концепция std::decay_t ). Для операции, которую в других языках посчитали достаточно распространённой, чтобы ввести в язык отдельное ключевое слово.
И вот в плюсах со всем так. В любой программе у вас будет минимум два вида строк, минимум два вида массивов, и вместо того, чтобы думать над бизнес-логикой, вы будете бороться с языком и гуглить, как это реализовали сверхразумы из крупнейших компаний.
Ну так а я о чём?
Я хз. Есть ощущение, что о том, в чем не разбираетесь.
27 строк бойлерплейта
И что? Этот бойлерплейт пишется один раз в какой-нибудь пространстве имен utils и используется по мере надобности. Причем не так часто, как вам может показаться.
В C++ это обычное дело. Точно так же было с хэш-таблицами до C++11 (да и после, т.к. std::unordered_map не всех устраивает), со string_view до C++17, с std::expected до C++23 и т.д., и т.п.
причём ну не джуниорского уровня
Проекты не пишутся джуниорами. Ну это я так, если вы вдруг не знали.
Причем вне зависимости от языка программирования. А уж на C++ тем более.
Для операции, которую в других языках посчитали достаточно распространённой, чтобы ввести в язык отдельное ключевое слово.
В других языках посчитали нужным и сборщик мусора в язык затащить. Давайте C++у в вину еще и отсутствие GC поставим.
В любой программе у вас будет минимум два вида строк, минимум два вида массивов
В современных условиях такое возможно только если:
a) вы имеете дело с легаси.
b) вам реально нужны эти разные типы строк и массивов. Скажем, исходя из требований по производительности/предсказуемости.
вместо того, чтобы думать над бизнес-логикой, вы будете бороться с языком и гуглить, как это реализовали сверхразумы из крупнейших компаний
Вы эти сказки таким же знатокам C++ как вы расскажите. Тогда найдете благодарную аудиторию.
На практике же приходится гуглить не какие-то особенности C++ или реализацию каких-то утилитарных вещей, а детали работы условного FFMPEG и SDL. Или пояснения к спецификациям каких-то протоколов. Или еще что-то в таком же роде, что гораздо ближе к проблемам бизнес-логики, чем отсутствие finally в языке.
Не то чтобы я очень хотел участвовать в дискуссии с аргументами уровня "если вы такие умные, почему вы строем не хо плюсы не учите", но ок.
Этот бойлерплейт пишется один раз
Он (конкретно finally/defer) должен быть если не ключевым словом, то хотя бы в стандартной библиотеке. Так же, как какой-нибудь парсинг json и функциональные литералы.
В C++ это обычное дело.
Вот именно. В этой части проекта у нас QT, в этой eastl, здесь кто-то скопипастил неизвестно что со stackoverflow, здесь мы сами наколхозили, а теперь мы попробуем найти ещё одного неудачника в нашу команду.
Проекты не пишутся джуниорами.
Ага, а миддлы с сеньёрами размножаются клонированием. (spoiler: увы, нет)
Из миддла-плюсовика можно сделать миддла-гофера за две недели. Ещё через пару месяцев он запомнит наименования местных функций, все три "паттерна программирования", станет синьёром и будет счастлив. А вот обратный процесс займёт пару лет боли и страданий.
Давайте C++у в вину еще и отсутствие GC поставим.
А давайте! Сколько там уже было попыток сделать хотя бы тупейший подсчёт ссылок в стандартной библиотеке? Не считая испытательных полигонов уровня mfc, qt, boost, mc++ и так далее? И чсх до сих пор нормально не осилили.
И да, в расте тоже нет GC, но качество управления памятью в нём просто с другой планеты.
вы имеете дело с легаси ...
Мне трудно себе представить новый (без легаси) проект на плюсах, который бы не взаимодействовал с ОС, системными либами, не использовал бы интринсики и т.д. А там везде массивы в стиле С, строки в стиле С, обработка ошибок в стиле С (вместо исключений) и так далее.
Вы эти сказки таким же знатокам C++ как вы расскажите
Ну, раз дошло до личных советов, посоветую вам высунуть голову из ... норы и поинтересоваться, что там в индустрии за последние 20 лет случилось. А там, блин, долбаный js развивается в 10 раз быстрее плюсов. А там плюсы — последний популярный язык, который не умеет нормально в utf8 "из коробки". (Да-да, сейчас мне расскажут, что умеет - на том же уровне, что и finally и дружит со всеми БД)
Не то чтобы я очень хотел участвовать в дискуссии с
Не то, чтобы я очень хотел участвовать в дискуссии с тем, кто C++ видел разве что в подобных срачах, но...
Он (конкретно finally/defer) должен быть если не ключевым словом, то хотя бы в стандартной библиотеке.
Не должен. finally/defer нужны языкам без детерминированого времени жизни объектов, т.к. там без finally/defer сложно детерминировано управлять ресурсами. Да и то, в Java к finally в итоге добавили try-with-resources, а в C# -- using. Так что сам по себе finally не так уж хорош.
В C++ с детерминированным управлением ресурсами все хорошо с самого начала, так что надобность в finally всегда была гораздо ниже, чем в языках с GC. В тех редких случаях, когда finally таки был нужен, можно было пользоваться паллиативами (BOOST_SCOPE_EXIT, gsl::finally и т.д.) Причем язык позволял создавать эти паллиативы на коленке. Попробуйте на коленке сделать defer для Go.
Впрочем, в C++ный стандарт сейчас так активно пихают всякое разное, что я не удивлюсь появлению finally в стандартной библиотеке где-нибудь в C++26 или C++29.
Так же, как какой-нибудь парсинг json
Вот этого не нужно. Во-первых, кроме JSON есть XML, YAML, TOML. И еще неизвестно что появится позже. Кстати говоря, лет 15 назад про JSON мало кто знал, а вот сожаления об отсутствии XML-я в stdlib высказывались. Сейчас вот XML уже не вспоминают особо, а будь он в stdlib, кому-то все бы это пришлось поддерживать.
Во-вторых, я не верю в то, что для того же JSON-а сделают библиотеку, которая одновременно будет и быстрой, и удобной в использовании. Включат в stdlib RapidJSON, будут ругать за неудобство, включат в stdlib nlohman::json, будут ругать за тормознутость.
Такие вещи лучше под условия конкретного проекта выбирать.
функциональные литералы.
Что это такое?
Вот именно.
Вот именно что? Если для GUI вы взяли Qt а для около реалтаймовой части EASTL, то в чем собственно проблема?
Ага, а миддлы с сеньёрами размножаются клонированием. (spoiler: увы, нет)
И какой вывод из того, что они не размножаются клонированием? Дать порулить C++ным проектом джуниору?
Из миддла-плюсовика можно сделать миддла-гофера за две недели.... А вот обратный процесс займёт пару лет боли и страданий.
А зачем вам обратный процесс? Неужели из-за того, что на Go сложно будет решать задачи, которые решаются на C++?
А давайте!
Предлагать добавить GC в C++ и жалеть об отсутствии GC в С++ в конце 2022-го года можно только от небольшого ума, уж простите. Время уже давно все расставило по своим местам: C++ с GC не нужен. Благо альтернатив с GC, хоть managed, хоть native, в достатке.
И чсх до сих пор нормально не осилили.
И не осилят. ЕМНИП, последние кусочки из стандарта, которые хоть как-то предполагали наличие опционального GC, были в конце-концов выброшены.
И да, в расте тоже нет GC, но качество управления памятью в нём просто с другой планеты.
Ну было бы странно, если бы язык, создававшийся на замену C++ и с учетом проблем C++, был бы в этом отношении хуже C++.
Мне трудно себе представить новый (без легаси) проект на плюсах, который бы не взаимодействовал с ОС, системными либами, не использовал бы интринсики и т.д. А там везде массивы в стиле С, строки в стиле С, обработка ошибок в стиле С (вместо исключений) и так далее.
Вы не поверите, но массивы в стиле С и строки в стиле C прекрасно закрываются std::vector и std::basic_string. И обработка ошибок несложно трансформируется либо в использование исключение, либо в применение чего-то вроде std::expected.
Ну, раз дошло до личных советов, посоветую вам высунуть голову из ... норы и поинтересоваться, что там в индустрии за последние 20 лет случилось.
Да я как бы наслышан. Вот только C++, местами, все еще актуален.
А там, блин, долбаный js развивается в 10 раз быстрее плюсов.
C++ всегда развивался быстрее, чем поспевали компиляторостроители. За редким исключением в районе C++14/C++17 стандартов, когда реализация подъезжала практически одновременно с выходом фиальной версии стандарта.
А так-то уже C++20 два года назад принят, но только один компилятор сейчас его более-менее поддерживает. С принятия C++17 уже почти пять лет прошло, а в GCC/clang еще не все хорошо с поддержкой stdlib из C++17 (например, std::to_chars/std::from_chars).
И это еще не говоря о том, что в мире C++ многие еще даже на C++17 перейти не могут в силу разных обстоятельств.
Так что C++ развивается, как по мне, даже быстрее, чем хотелось бы.
Ну и да, еще на счет "за последние 20 лет случилось".
Это ведь еще сильно зависит от предметной области. Если вам в 2022-ом потребуется сделать форк Greenplum или MariaDB, заточенный под специфические нужды, или нужно будет начать делать кроссплатформенный видеоредактор, то скорость обрастания фичами JS-а или нововведения в Go вам вряд ли помогут.
либо создавать аж целый класс ради вызова операции В в его деструкторе
И вишенка на торте: из деструкторов нельзя бросать исключения.
Если операция B, равно как операция A, может бросить исключение, придётся забыть про RAII и писать очень кривой код.
Если Вам из деструкторов нужно кидать исключения, то у меня очень плохие новости об архитектуре проекта, который Вы пишете...
А вот исключение из finally — штука совершенно нормальная, пусть и редкая. Проблемы начинаются когда finally реализуют через деструкторы...
А вот исключение из finally — штука совершенно нормальная
Нормальная в том смысле, что не приводит к прерыванию работы приложения, так надо понимать?
Просто код finally обычные разработчики пишут так, как будто в самом finally исключения не выбрасываются поэтому можно делать действия A, B и C не заботясь о том, что каждое из них может бросить исключение.
goto и метки с глобальным еррор кодом это медленнее, чем С++ исключения. Потому что еррор коды нужно проверять постоянно при каждом вызове, тогда как исключения используют особый свой механизм, позволяющий избежать оверхеда на эти проверки
goto не задействует RAII и сильно сказывается на возможности оптимизации кода, который выпрыгнул хз куда
Ну и да, goto так не работает, вы либо имели в виду setjmp, либо непонятно что
std::string ЛУЧШЕ чем cow строка, именно поэтому отказались от cow и сделали то что сейчас. cow это вообще крайне стрёмная херня, пользы от неё примерно 0
Выше приведен вполне реальный пример, когда благодаря CoW-строкам мужики неплохо ужались по памяти.
Такое может произойти только в очень плохом коде, где вместо стринг вью или ссылки делают новую строку копируя или что-то такое
Отказались от cow потому что оно по всем параметрам хуже. Инвалидация итераторов это лишь малая часть
Простой goto в сишных проектах встречается для обработки ошибок гораздо чаще, чем setjmp.
goto не может заменить исключения. Его в С используют только потому что там нет RAII и нужно прыгать на clear_rcrs или что-то такое
У стандартизаторов есть такая мысль, что алгоритмы должны работать одинаково во всех случаях. Например, есть более эффективные в обычных применениях алгоритмы сортировки, а ещё можно было бы специализировать сортировку на конкретные типы численные типы и сделать её на них за O(n), но в С++ намеренно сделано не так. Сделано это из соображений стабильности (чтобы не было внезапных лагов как в языках с GC) и безопасности (чтобы нельзя было подобрать предельный случай и поломать приложение).
CoW-строками, потребляют слишком рандомное время на ряд операций. Банальное обращение к элементу может в зависимости от имплементации быть O(log N) или O(N), хотя пользователь ожидает O(1). Именно это стреляет по ногам джаваскриптерам при работе со строками (это же совершенно очевидно, что их нужно сплитить в массив по одной букве перед тяжёлыми вычислениями). Именно поэтому их нет в стандартной библиотеке С++, и не будет.
Работа на С++, конечно, не сахар, но хорошо что он развивается, тем самым облегчает жизнь.
Хотелось бы добавить пару слов об образовательной части C++ — это отличный способ углубиться в понимание устройства процессов железа, особенно после таких языков, как C# и Java. Более того, после изучения курса по алгоритмам и структурам данных, начинаешь более вдумчиво и ответственно писать код, предварительно успев отстрелить себе несколько раз ногу. Однако C++ не стоит рассматривать как первый для изучения ЯП. Для новичков лучше начинать свой путь с Python (можно без ООП), далее перейти на C# или Java, а затем уже погрузиться в мир указателей, динамической памяти и множественного наследования.
по поводу слайда сравнения используемых ресурсов (СО и прочего), вспоминается анекдот:
Жизнь слишком коротка, чтобы писать на ассемблере С++ (с)
Есть даже широкоизвестный закон Проебстинга: компиляторы увеличивают производительность кода в два раза каждые 18 лет.
Использование С++ не имеет никакого смысла, если размер задач не подразумевает миллионные убытки на электроэнергию и вычислительные мощности.
Зачем писать на C++ в 2022 году?
Потому что это лучший язык на земле?
Но статья немного странная, если честно, обычно когда у вас есть проект вы уже представляете какие варианты по языкам. Даже если очень любишь C++, есть задачи явно не для этого языка, как и наоборот.
В то же время одной из суперсил C++ является обратная совместимость.
Суперсилы нужно правильно применять. Вот в расте покумекали-покумекали, и сделали редакции. Старый код на старой, новый — на новой. Очень сомневаюсь, что возможность раз в десятилетие скомпилировать чей-то курсовик 40-летней давности стоит того, чтобы все остальные разработчики хватались за голову, разбираясь, что же сейчас стоит использовать, а что уже нет.
Более того, что мешает скомпилировать объектники старым компилятором и подать их на вход новому линкеру? Думаю, их формат действительно совместимый, т.к. меняться там скорее всего особо нечему.
Есть там чему меняться
Обратная совместимость очень важная вещь. В каком нибудь линуксе PHP написанный на 5 версии, отказывается работать на 7 (следующей). Так быть не должно.
Вы видели процесс обновления С++ компилятора в большом проекте? Это месяцы работы большой специально выделенной команды. И с практически 100% багами в проде после перехода.
Это не совместимость.
Похоже, что зависит от степени запущенности проекта.
Повырубав кучу ворнингов заставить компиляться и работать не так уж сложно и долго. А потом да, постепенно эти ворнинги исправлять параллельно с разработкой в течение месяцев. Самое удивительное, что когда потом включаешь обратно эти трактуемые как ошибки предупреждения, оказывается, что они вообще-то были очень даже по делу, и фактически работа проводилась вовсе не ради галочки, а сделала продукт стабильнее и лучше.
Другими словами, при переходе на новый стандарт основные проблемы, кмк, возникают именно из-за более чувствительных к ошибкам и нарушению стандарта компиляторов, а отнюдь не прихоти.
Тяжелее всего должен быть переход C++98 на 11, поскольку в древнем C++ очень многие вещи делались абы как и с явным уб, без которого жить было невозможно в принципе(те же потоки)
Питон 3 должен войти во все учебники как делать не надо. Хуже сделать наверно невозможно. Не надо равняться на худших.
Ну вот. Несколько месяцев. Примерно как я и написал. Рост трудозатрат от размера проекта совсем не линейный. Давно забытые куски которые в проде, но они никому не принадлежат, в больших плюсовых проектах тоже бывают.
А при чем тут линукс вообще ?
Вы мне напомнили, как в универе нам однажды выдали пример интерпретатора на Си. На таком древнем Си, что он уже даже компиляторами не компилируется. Там типы аргументов объявлялись между ) и {, например.
Компилятор Rust поддерживает все три редакции в одно и тоже время (в разумных пределах конечно, например нельзя требовать от компилятора 2018 г., поддержку редакции 2022). То есть например с последним rustc 1.65.0 можно компилировать и писать в редакциях 2015, 2018, 2021.
Кроме того, он позволяет мешать разные редакции на уровне библиотек.
То есть налицо обратная совместимость. Просто в новой редакции можно использовать что то новое, более гибкое, и, что уж греха таить, иногда нельзя использовать что то из старого. Если это старое позарез нужно, то просто не переходи на новую редакцию, благо стандартная библиотека, если я точно помню, предназначена для всех редакций.
Если исключить из всех существующих программерских задач веб-разработку, то, собственно, какие ещё останутся пригодные языки, кроме C и C++?
Java и Python.
Можете из головы назвать пяток более-менее широкоупотребляемых программ, написанных на питоне?
Не могу, но это не значит, что язык не применяется в разработке. В Blender'е на нём скрипты, например, реализующие часть функционала. Есть игровой движок PyGame с мелким, но всё же какими-то реальными проектами (Frets of Fire), и в целом в различных игровых движках скриптовая часть нередко реализована на нём. Разнообразный научный софт часто написан на Питоне.
О, точно, Ren'Py же и всё на нём написанное, включая БЛ!
Ещё знаю Electrum и производные от него.
Вот уже целых две питонопрограммы. Ура.
Сложность питоноскриптов блендера надо посмотреть - вдруг они тоже реально что-то делают. Будет три.
Дополнительно вспомнил virt-manager и youtube-dl со товарищи.
sublime (был несколько лет назад вполне себе популярным текстовым редактором)
Всякие системные сервисы в Ubuntu достаточно широкоупотребимые программы?
Кроме массы всего связанного с data science, ML и т.д. где Python стандарт де-факто?
Ansible, Manim, micropython, httppie, localstack.
Go тоже вариант иногда
а вы попробуйте снести весь питон с убунты (и второй и третий) а потом запустить какой-нить sudo apt
Они даже не компилируемые.
Практически все и останутся
Я готов согласиться, когда речь идет о плоских C. Но ОДНА база данных из всех (остальные не на плюсах) кажется мне вполне себе показателем.
Я конечно люблю кресты, но мне одному кажется (?) что вот это:
// теперь мы можем написать
Пример того как писать не надо? Ну окей, это короче, но совершенно нечитаемо... Может я застрял в embedded конечно, но выглядит гораздо хуже тривиального цикла приведённого выше.
auto isEven = [](auto number) { return number % 2 == 0; };
auto count = std::ranges::count_if(numbers, isEven);
Холивара ради: а ведь говорят, что у Rust ужасный синтаксис.
let count = numbers.iter().filter(|number| *number % 2 == 0).count();
Это на любом нормальном языке примерно одинаково выглядит.
Завидовать можно дотнетовскому LINQ. Вот он хорош и совсем не везде такой же есть.
section'ы и частичное применение из коробки есть, мягко скажем, не везде.
Явно есть много где. Бойлерплейт это печально, но это терпимая плата за упрощение языка.
Частный случай do-нотации.
Сделанная для людей, а не как обычно. И то много жалоб что слишком сложно.
Наверное, потому, что простота языка — далеко не единственный и даже не монотонный критерий
Смотрю я на популярность Go и начинаю сомневаться.
Я за баланс. До уровня Go падать не стоит, а вот тот же С++ или Хаскель (смотря из какого вы лагеря) это перебор. Лучше всего посередине.
На LINQ парсеры люди, конечно, тоже пишут, вроде даже на хабре статья была, но это уже совсем извращение ИМХО
Пишут. Нормально выходит вообще. Опять не идеально, но нормально.
Для массового языка это достижение. На других массовых языках в среднем хуже выходит.
Это всё от, как там, интеллектуальной небрежности.
Мир не совершенен.
Популярность — это вообще вопрос такой, неоднозначный
Я обычно по количеству вакансий смотрю. Остальное зависит от окружения.
а с хаскелем что слишком сложно?
Концепции слишком сложные. Люди их не понимают. Я бы сказал что средний мидл может не понять. Возможно учат плохо, не знаю.
Я на собеседованиях на Джаву уже отчаялся и больше не прошу собеседующихся на мидла своими словами рассказать мне как работает и что делает flatMap. Валятся в общем-то нормальные разработчики.
То есть, делать закат солнца вручную на неприспособленных к этому инструментах (метапрограммирование на темплейтах, парсеры на linq, etc) — это норм, а потратить вечер на специально созданную для соответствующих задач концепцию — сложно?
Ага. Я беру типичного мидла и отправляю его дописать очередной визитор в существующий проект. Со второго раза он точно справится. Две недели на обучение, наверно.
А вот в том что он за хотя бы пару месяцев освоит специальный язык на уровне достаточном чтобы понять и дописать тот же визитор в существующий проект немаленького размера я совсем не уверен.
Как-то глобально что-то поменять в существующем проекте он не сможет ни в том ни в другом случае. Тут равенство.
А те кто могут и пишут просто смирились уже. В конце концов бывает и хуже. Люди вон на плюсах пишут такие же штуки еще и с мутирующим стейтом где-то глубоко внутри. Вот это настоящее страдание.
Количество вакансий тоже зависит. Вы ж не ищете просто вакансии «программист», наверное?
Да. По настроению добавляю зарплата не указана и вычеркиваю все окологос конторы. Они не указывают зарплаты от бедности.
Причём я бы ещё сказал, что вся эта функциональщина — это куда проще, чем ООП
ООП хорошо вдалбливают в институтах. Прям несколько лет обычно. С кучей экзаменов, курсовых и прочего.
А функциональщина остается на уровне полугода Лиспа в лучшем случае. И то там не придираются к тому что человек не смог обычную курсовую написать. Когда пишут за него это хорошо видно.
Не, я охотно верю, что есть люди, которые не могут осознать, что такое IComparable, как должны быть связаны сравнения и хешкоды, и всё такое, но что они делают в программировании? Зачем они вам нужны как нанимателю? Зачем вам как работнику работать среди таких людей? Зачем вам как клиенту пользоваться софтом, произведённым такими людьми?
Джейсоны должны быть переложены. Для этого не очень много знаний надо. Про квадрат и мапы знает, несложный код в режиме live coding написать может и ладно. И то люди даже без такого уровня знаний приходят регулярно.
ЧТД, действительно был бы отличный фильтр.
Для людей с сеньорами, архитекторами и еще много страшных слов в резюме на вакансию программиста я оставил этот вопрос. Даже из них отсеивается немало. Прям сразу за 5-10 минут все понятно.
Ну и, то есть, сама концепция flatMap (который есть и в Джаве, и в JS, и много где ещё) для них слишком сложная? Так тут не язык виноват, концепции-то есть вне языков.
Да. Скопипастить готовый кусок и немного подправить под свой случай могут. Объяснить как работает нет. Концепцию не понимают. Синтаксис пофиг. Я именно про концепции.
Концепции слишком сложные
Да, там на первых порах случайно ввели в язык монады, а надо было вводить какие-нибудь эффекты, но тогда люди ещё не знали. И с ленивостью по умолчанию тоже вышло так себе. Ну и там с monomorphism restriction стрёмно немного. И в целом compile-type prolog в тайпклассах это немного не то, чем должен заниматься человек, которому нужно код в продакшен писать.
Зато во всех остальных отношениях Haskell элементарен и прост.
Ну в джаве дженерики так-то тоже Тьюринг-полные
Так в Haskell и без Тьюринг-полноты оно недружелюбно. Без MPTC и FunDeps не типизируется и весьма простой код, а с ними как-то более хардкорно, чем хотелось бы ожидать от банальной перегрузки.
К счастью, есть
-XNoMonomorphismRestriction
Но он же никак не решает коренную проблему: неявную мемоизацию, включаемую только чисто синтаксически. Вроде бы как язык чистый, а тут какой-то стейт появляется.
рассуждать о производительности в ФП вообще сложновато
Вообще практика показывает, что только в ФП и можно вообще о ней рассуждать, потому что как раз через equational reasoning можно выводить алгебраически (формализмом Бёрда-Меертенса, например) алгоритмы с лучшей асимптотикой, чем в спецификации, а без ФП можно только что-то эдакое наваять и понадеяться, что нигде нет ошибок.
Проблема только в конкретном сорте ФП, с нормальным порядком редукции, который меняет асимптотику от малейших правок и рандомно.
Почитал тут вашу ветку, и хочу кинуть камень в огород Haskell. Ни в каком другом языке я не встречал настолько отвратительной документации к библиотекам, как там. У плюсовых библиотек тоже часто с этим печально бывает, но обычно не настолько. Пример - дока по Lens - дается куча каких-то выражений на Haskell, и разбирайся с этим сам. Ну и нейминг зачастую как в математике - куча каких то одиночных букв и операторов, от которых глаза слезятся.
Где тут игра в пролог?
Очевидно, в том месте, где инстансы матчатся по типу, а не в определении класса.
Тайпклассы — это такой сахарок для передачи словарей функций + алгоритм их разрешения
Это и называется перегрузкой. Вам бы надо обязательно попросить Simon Peyton Jones тоже использовать расово верные эпитеты, а то у него иногда проскакивает. От недостатка образования в ФП, наверное.
Зачем так сделано — действительно непонятно.
Вас не смущает, что чистота — она в, собственно, языке, а стейт (который не стейт, а на самом деле вывод не-most-general-type, который в этой решётке оказывается, удивительно, не единственным) — в движке вывода типов?
Вас не смущает, что вы вообще не представляете, о чём говорите? :)
Ознакомьтесь, пожалуйста, с матчастью хотя бы в haskellwiki и спилите мушку.
это тоже перегрузка, что ли?
Любой случай, когда у вас имплементация при вызове выбирается на основе типа, принято называть перегрузкой. Спор о терминах -- ну такое. Можно с тем же успехом утверждать, что Java -- не ООП, потому что в ней LSP не работает, или что Си -- функциональный язык, потому что там есть first-class function pointers. Эта казуистика на практике бессмысленна, и вам ничем не поможет.
Апелляции к авторитету — ну такое.
Ну да, апеллировать к автору тайпклассов и HaskellWiki нельзя. Их только неудачники читают, чтобы вас публично уязвить.
Ну, в смысле, я-то как раз понимаю, о чём говорю.
Хорошо, давайте по существу, если Даннинг и Крюгер не позволяют вам разобраться самостоятельно.
Когда тайпклассы имплементят через dictionary passing, получается проблемка: вещи, которые раньше были просто значениями, становятся функциями. Например, когда мы пишем
fib = 0 : 1 : zipWith (+) fib (tail fib)
и для него (гипотетически) выводится тип (Num a) => [a]
, то на самом деле получается
fib d@{fromInteger, add} = fromInteger 0 : fromInteger 1 : zipWith add (fib d) (tail $ fib d)
исполняющийся за экспоненциальное время. Собственно, об этом нам прямым текстом пишут в секции 4.5.5 стандарта языка, которую вы так и не удосужились прочесть.
С тех пор, конечно же, ребята догадались, что мономорфизация/инлайнинг, в общем-то, не сильно хуже, чем dictionary passing, разве только с полиморфной рекурсией не работают, и GHC сейчас компилирует код иначе.
Мемоизация (на самом деле, CAF, но неважно), кстати, довольно часто используется, чтобы гарантировать, что какой-то код исполнился не больше одного раза, и вопрос "не выведутся ли тут типы, которые превратят этот код в экспоненциальный" внезапно становится крайне важным.
Вам бы пришлось узнать, как оно там на самом деле работает, если бы попробовали всё-таки сфокусироваться на этом и написать хоть какой-то тривиальный производительный код. На практике это полезнее, чем разбираться в тонкостях Has
.
перекладывания жсонов — как часто при среднем перекладывании этих самых жсонов вам надо делать подобные Фибоначчи, завязывать узлы из двусвязных списков, и заниматься прочими непотребствами, где приходилось бы думать о том, что, когда и как именно будет вычисляться
Вообще бывает. Не то чтобы каждый раз, но встречается временами. Бизнес логика довольно веселой бывает. А докинув немного бигдаты и хайлоада в эту бизнес логику вообще весело получается.
Гарантия сложности не хуже логарифма в случаях когда программист явно не написал более медленный алгоритм обязательно нужна. Ловить внезапный и тем более неявный квадрат в проде не хочется. Это ничем не лучше ловли медленно текущей памяти.
Теперь у меня есть хороший аргумент почему Хаскелю не место в проде. Будем и дальше писать на более обычных языках. Где все проблемы производительности довольно очевидны.
У вас как-то интересно получается. То люди без развитых когнитивных навыков для возможности понять flatMap пригождаются (и это аргумент против «сложных» языков), то надо писать сложные алгоритмы бигдата хайлоад бизнес-логика (и это снова аргумент против «сложных» языков).
Плодить языки в проекте без надобности не надо. Значит большая часть будет на одном языке. А это и простое перекладывание и что-то хитро наверченное рядом. Писать могут разные люди, это да. Проект не без нормальных сеньоров.
Ну да, не так давно статья про go пробегала, где от замены одного символа она в полтора раза быстрее работать стала. Проблемы довольно очевидны!
Отладкой проблем производительности в плюсах я вообще отчасти зарабатывал себе на жизнь некоторое время. Джава-люди вон тоже себе всё время то бенчмаркают что-то, то GC тюнят. Было бы всё очевидно — наверное, они бы этим не занимались.
Все таким занимаются. Я даже знаю пару мест куда готовы нанимать просто на оптимизацию людей. Хоть команду возьмут. На очень неплохие деньги.
Но это оптимизация критического пути или еще чего-то еще очень маленького от общего количества кода. В большей части кода это все не играет роли. Полтора раза от пары миллисекунд в каком-то методе на который нагрузка 1 рпс? Не интересно.
А вот квадраты взрываются во всем коде. Миллион штук пользователи запихнуть во все дырки догадаются. В нет ни одной причины почему это не должно нормально не отработать.
Ну вот нормальные синьоры нормально и напишут.
Конечно. Но хочется чтобы язык им в этом не мешал.
Так обсуждаемые вещи вылезают плюс-минус настолько же редко, как критические пути. Примерно на уровне захвата тяжёлого объекта в плюсах в лямбду по значению, а не по ссылке, или чему-нибудь подобному.
Проблема в неявности этого. Глядя на код тяжелый объект можно увидеть. Критический путь обычно известен еще на этапе разработки и тестирования. А вот такая подстава от языка/компилятора может прилететь в любой момент в любом месте. Как ее увидеть заранее я пока не понимаю. Прям UB родной.
Ага
Убедили. Бывает совсем неочевидно.
В итоге заменяем одни сложно обнаруживаемые проблемы на другие.
От всей функциональщины хочется гарантий, а не вот таких проблем. Гарантия корректности это великолепно. А можно еще гарантию неквадратности при прямых руках разработчика приложить? Ругань при компиляции с каким-нибудь ключиком подойдет.
Теперь у меня есть хороший аргумент почему Хаскелю не место в проде. Будем и дальше писать на более обычных языках. Где все проблемы производительности довольно очевидны.
Так Х-ь в продакшен тащить без надобности никто и не рекомендует. Посмотрите, где его большие компании используют.
Например, Github на нём сделал Semantic для эдакого IntelliSense, поддерживающего дофига языков. У них есть статейка "зачем хаскелл", в которой на много слов объясняется, что они бы на чём-то другом просто не смогли написать по причине большого количества букв. Гитхаб -- вполне бигдата.
Facebook'у нужно было разгребать тонны спама и прочего модерируемого контента, быстро модифицировать код под очередные хитрости спамеров и не ошибаться. Так нужно, что они автора рантайма Haskell наняли процессом руководить. Каждый пост на фейсбуке тоже звучит вполне как бигдата.
Другое дело, что если посмотреть, какой уровень профессионализма должен быть у людей, которые этим занимаются, сразу становится немного грустно.
Лично мои аргументы, почему хаскеллю не место в проде, это инструментарий и инфраструктура. Под хаскелль нет нормальных средств разработки и отладки, и у него все плохо с библиотеками и фреймворками. Пробовал ради интереса создать простенький хеллоуворлд рест сервис, который умеет писать "хеллоу" в БД, так я с зависимостями и кофликтами версий разных либ прям запарился. И это при том, что я использовал stack, который решает кучу вопросов из этой серии. В общем хаскеллю сильно не хватает своего maven и своего spring boot. Ну и чего-то уровня Idea тоже хотелось бы.
У плюсов есть CLion, у хаскелля только плагин к идее, и это лучшее, что я видел из средств разработки под Haskell.
Отладка - кому как. Мне нужно. Я хочу ставить брекпойнты в ИДЕ, смотреть данные вживую, и писать куски кода внутри окошка evaluate expression, чтобы там был весь текущий контекст типа подключения к БД и прочего. У хаскелля только консольный недоотладчик, интеграции с редактором не видел.
Простенький проект у меня не получился со следующими штуками: stack для сборки и управления зависимостями. Snap в качестве веб-фреймворка. HDBC для работы с БД. Data.Aeson для JSON сериализации/десериализации. Вот вроде основное, что вспоминается. Поглядел сейчас на stackage, в текущем срезе lts 20.2 Snap отсутствует, добавлял его руками, и в итоге получал конфликт версий Base в транзитивных зависимостях после добавления HDBC и еще нескольких либ.
P.S. Эталоном инструментов разработки для меня является Idea или VisualStudio + ReSharper. Сравниваю все остальное с ними.
До CLion я для плюсов пользовался NetBeans'ом, но это было давно, в 2011-2015 примерно - писал всякие алгоритмы для аспирантуры. QtCreator довольно неплох, и тоже давно существует. VisualStudio мне лично не зашла, про нее ничего хорошего сказать не могу. Концепция редактор + плагины мне лично не заходит, хочу интегрированную среду разработки, чтоб вязл, и там сразу все есть. См. выше про идею.
Это называется repl. Зачем вам отладчик, когда у вас есть полноценный repl?
Вам вот заходит REPL, а я хочу отладчик. Хочу тыкать в IDE брекпойнты, смотреть как идет выполнение кода в разных случаях, видеть какие там реально данные за абстракциями спрятаны. REPL такой возможности не дает (или дает в неудобном для меня виде).
Но почему не servant?
Потому, что это был мой эксперимент с хаскеллем, и я захотел использовать Snap, деталей уже не помню, но чем-то он мне приглянулся. Возможно, понравилась их концепция снаплетов. С плюсами я таких проблем с зависимостями не помню, там вообще нечасто транзитивные зависимости мне попадались. Обычно цепочки зависимостей в плюсах, что я встречал, выглядели в стиле "библиотека для математики хочет blas и lapack, или что-то совместимое с ними".
Она до сих пор (clion, по крайней мере) даёт вполне ощутимый лаг при наборе текста.
Мне скорость именно набора вообще некритична, примерно 80% текста, что я пишу в IDE, она сама мне и генерирует, через всякие автоподстановки аргументов и прочие механизмы вроде Ctrl+Space, Alt+Enter и т. д. Мне больше важно, насколько хорошо IDE понимает контекст, и умеет в подстановку кода. Например написал obj->, получил список методов. Выбрал метод из списка, хочу подсказки по аргументам, да чтобы в соответствии с типами, именами и т. д. Или жмакнул хоткей на классе, получил заготовку юнит-теста для него.
Если мы начнём говорить о личных предпочтениях, то можно ли сказать, что джава для прода не подходит, потому что там репла нет?
Для моего прода подходит, для вашего видимо нет.
которого даже нет в том же stackage LTS, и в результате вы ругаетесь на проблемы с версиями и то, что его нет stackage, и поэтому там нет фреймворков для реста?
Скорее претензия к тому, что я беру понравившийся мне фреймворк, понравившийся мне драйвер к БД и сразу, сходу получаю проблемы. В той же Java я тоже сталкивался с проблемами зависимостей версий библиотек, и их не очень хорошей совместимостью с определенной версией application server, но там я столкнулся с этим один раз за примерно 8 лет работы, а не вот так вот сходу.
Ну а у меня конкретно в продакшене было, что одна библиотека требует C++03, а другая — C++11, и там бинарно несовместимые куски STL, поэтому получается весело.
Как я написал выше, бывает даже в Java. Вопрос, сколько раз и за какой период вы с этим сталкивались.
Для того, чтобы этот вопрос не был при этом и сложным, достаточно просто указывать типы подобных байндингов.
О том же, блин, речь и шла, что вот такие детские грабли положены, и наступать на них ну очень неприятно.
Ну а возвращаясь к нашему исходному вопросу о пригодности х-ля для перекладывания жсонов — как часто при среднем перекладывании этих самых жсонов вам надо делать подобные Фибоначчи, завязывать узлы из двусвязных списков, и заниматься прочими непотребствами, где приходилось бы думать о том, что, когда и как именно будет вычисляться?
Как раз при перекладывании жсонов AST и наступал. Я лично считаю, что тут очень хорошее место для того, чтобы передизайнить язык.
В коболах есть!
:) к вашему рефакторингу теперь комменты нужны. а иначе нужно голову включать что предикат делает
Эта строчка многих читающих код заставит споткнуться на ней и думать что же там происходит. Зачем это надо? Можно же нормально написать. Чтобы человек читающий код не думал, а просто шел дальше.
Я бы на кодревью зарубил с комментарием "Надо переписать понятнее"
все таки есть разница между isEven
и каким-либо выражением, независимо от его сложности
Согласен, нечитаемо. Зачем отдельно объявлять isEven?
Как представитель племени мамонтов, я бы все-таки предпочел сначала объявить isEven, хотя в нашем заповеднике это требует отдельного танца:
MODULE MyNumericTests
...
CONTAINS
...
logical elemental function isEven(i)
integer, intent(in) :: i
isEven=(mod(i,2) == 0)
end function isEven
...
END MODULE MyNumericTests
Да, многословно... но обычно модуль типа MyNumericTests содержит не одну функцию, а целую кучу, а заодно и структуры данных, с которыми они работают (по сути, это очень похоже на описание класса). И он пишется один раз. Зато в программе будет:
use MyNumericTests
integer :: iArray(5)=(/1,2,3,4,5/)
...
... =count(is_even(iarray))
...
О вкусах не спорят, но на мое скромное имхо этот синтаксис и компактнее, и понятнее приведенных выше примеров. Причем даже для тех, кто не знает, на каком языке это написано (надо только иметь самое общее представление о массивных операциях).
Желающие, конечно, могут обойтись и без isEven:
integer :: iArray(5)=(/1,2,3,4,5/)
integer :: counter
counter=count(mod(iArray,2) == 0)
Но с точки зрения фортраниста (который сам когда-то писал GO TO), фразу "вот так гораздо лучше" применительно к этому коду стоило бы все же сопроводить тегом </сарказм>
Для холивара
А чтобы не слишком отклоняться от темы статьи, выскажу еще одно провокационное мнение: если речь идет о простом перемалывании чисел (и только о нем!), то "писать на C++ в 2022 году" действительно незачем ;-) Так как фортран позволяет написать то же самое и настолько же эффективно программисту гораздо более низкой квалификации. Ибо современный фортран явно проще, чем современный же С++. А главное, при одинаковом уровне программиста понятность (читаемость) фортран-программы будет получше за счет массивных операций и более тривиального синтаксиса. Ну и отлаживать фортран явно проще, если только не стрелять себе в ногу умышленно (впрочем, это на любом языке можно сделать ;-).
Рискну предположить, что застряли не в embedded (где вполне можно писать так же, причем еще и практически zero-cost, так как операции над рейнджами очень хорошо инлайнятся и оптимизируются как по производительности, так и размеру исполняемого кода, то, в чем C++ реально хорош и почему все готовы терпеть медленную компиляцию), а в процедурном подходе и старой версии стандарта.
Современный подход, причем не только в C++, а почти во всех языках, подразумевает больший упор в функциональную парадигму: неизменяемые значения, широкое использование функций (в том числе анонимных), в частности в качестве аргументов и возвращаемых значений, отсутствие глобального состояния и декларативность. Привыкнув к этому, можно писать гораздо более надежные и читаемые программы как для микроконтроллеров, так и суперкомпьютеров.
Отнюдь, в современном JS как раз всё перечисленное (кроме может глобального состояния, но смотря что вы под этим понимаете) вполне привычно.
Однако, из того что вы перечислили "использование функций в качестве аргументов и возвращаемых значений", надежнее (что?) и читаемее код не делает никак.
К этому конечно можно привыкнуть (вопрос практики, разумеется), но это зачем, если на выходе компилятор выдаст ровно то же самое, а времени на понимание кода у среднестатистического разработчика уйдёт больше.
Что-то мне этот однострочник не кажется более читаемым. Обычный цикл сразу интуитивно понятен, а тут надо глаза и мозг ломать.
Статья не поднимает один важный вопрос. Зачем начинать новый большой проект на C++, если есть Rust?
Затем, что новый большой проект на Rust будет компилироваться даже дольше С++, потому что ребята на голубом глазу накоммитили тайпчекер за квадрат от количества определений алгоритмом Робинсона. Именно это, например, не позволило использовать Rust в OpenBSD.
Вот это, кстати, очень интересно. Есть ли какие-то исследования насчёт времени сборки? Работал с большими проектами на плюсах и хорошо представляю как это больно
Сборка Rust проектов и правда очень долгая, но только если компилировать проект первый раз. Далее включается инкрементальная сборка, и по сути затык во времени идёт только на этапе линковки. Но и для этого есть решение — использовать линковщик mold вместо стандартного (подменяется одной строчкой в конфиге cargo). И вжух — проблема времени компиляции уходит в принципе!
Там претензия скорее в другом: кто-то предложил "а давайте всё на Rust перепишем!", при этом сам не желая что-либо делать. Ну и ещё у автора текста требование, чтобы компилятор Rust компилировался на i386, что, честно говоря, странное требование.
я читал coders at work и там говорили, что С++ слишком сложен. А не С/С++. И это писал человек, который каждый день 20 языков использует:-)
Немного отвлеченный вопрос про углеродный след и его снижение. Приведен даже слайд с разницей в 10 раз между платформой на С/С++ и платформой на пхп/питоне/руби. А где оценка углеродного следа во время разработки этой платформы? Видится мне, что по энергозатратам на разработку сравнение будет не в пользу С++.
Сейчас на web собираются мигрировать, поскольку он кросс-платформенный, будет мол работать везде — хоть на десктопе, хоть на планшете. Уже уперлись в то что даже в UI-специфичном приложении использующем 3D половину вещей сделать сложно и оно тормозит. Ковыряют webassembly. А могли бы ведь с самого начала сделать Qt и все бы работало быстро и с минимумом переделок…
но мне сообщили что Qt разработчиков найти сложно а C# легко, язык так крутой и мы все что захотим сделаем, поддерживает hidpi
Это была очень странная информация, учитывая что направление десктопного UI в языке уже 6 лет как безнадёжно заброшено...
Вообще, на с++ писать не очень то и удобно. Рекомендую С#, это будет пожалуй получше чем С++. Кстати, можно и JavaScript компилировать в С# и использовать. 1 строка в js = 20 строк в С++
Старая фраза : Все языки делятся на две группы - одну все ругают, на второй никто не работает.
На мой взгляд, главная проблема C++ в том, что сделав его суперуниверсальным, его создатели не подумали о том, что часть этой универсальности стоило ограничить. В итоге получилось, что на каждую возможность стало появляться огромное количество антипаттернов. Язык накопил огромный технический долг, который сначала решался энтузиастами и потом через долгое время становился частью стандарта.
Вторая проблема, то что язык так и не оброс нормальными кросс-платформенными библиотеками, например для работы с сетью, БД или десктопом. Разрабатывая на C++ под винду и перейдя на линукс можно испытать огромную боль и гнев. В этом смысле С++ очень привязывает разраюотчика к компании. Мысли о смене работы улетучиваются, когда представляешь сколько всего предстоит сделать, изменить или изучить, чтобы создать для себя комфортные условия для работы на новом месте.
Ну и приложения где большую часть кода занимает ос-специфичное взаимодействие с сетью / БД или десктопом мне вообще кажется не очень подходят для C++.
Лицензионная политика Qt сейчас грабительская. Насколько я помню нужно платить роялти за каждый экземпляр программы.
Библиотек отличного качествам валом. Например, чем boost ASIO не подходит на роль библиотеки для работы с сетью?
Разрабатывая на C++ под винду и перейдя на линукс можно испытать огромную боль и гнев
Это скорее говорит о недостатке опыта в этой области конкретного разработчика. Да, нужен определенный опыт и определенные практики, но это не нечто запредельно сложное.
А что в плюсах с сетевыми библиотеками? Есть Asio, есть Qt, есть Poco. Чем вам они не подходят?
Хех, недавно вылез из своего Сишного подвала посмотреть на С++17 в эмбеде и мне в целом понравилось. Сразу столько вкусняшек из коробки, да еще и код часто бывает компактнее.
Автор хитрер, сравнивает C++ c Python, забывая о существовании Rust, Go, Java, C#.
const std::vector<int> numbers = {1, 2, 3, 4, 5};
// вместо
auto count = 0;
for (const auto& n : numbers) {
if ( n % 2 == 0) {
++count;
}
}
// теперь мы можем написать
auto isEven = [](auto number) { return number % 2 == 0; };
auto count = std::ranges::count_if(numbers, isEven);
В первом способе 82 символа, во втором - 110. Читаемость одинаковая, хоть и подход разный (функциональный и нет)
P.s. Зачем так много auto? И int по ссылке брать не стоит
Зачем писать на C++ в 2022 году?