Всем привет! Я хочу поднять тему неполноты stl, порог входа в С++ и его сложность. Обо всем, да по порядку.
На дворе 2020 год. Только-только вышел новый стандарт. Добавили кучу полезностей (Подробный список можно посмотреть здесь, а также в других статьях на хабре). Чего только нет в современном stl для базовых ситуаций. Многие все ещё ждут networking, мелочи, но все равно не очень понятно в чем проблема. Если взглянуть на boost, там есть и networking и ещё много всего, но проблема, к которой я веду, присутствует и там.
Так в чем же проблема? А проблема в том, что если взглянуть на документацию stl к какому-нибудь vector, то что там можно увидеть? Несколько методов да и только? Я не беру в расчёт перегруженные операторы и методы типа data и at. Итак, что у нас есть:
erase — безусловно нужный метод. Удаление элемента. Все ок, кроме… Почему erase? Почему не remove или delete? Это распространённая практика во многих языка. Это было бы очевиднее людям, которые приходят в C++ из других языков. Ладно, не буду придираться к названиям, хотя методы push_back и pop_back мне все же немного странно видеть. Зачем это лишнее back?
Ладно. Придрался к названиям. Разве это и есть неполнота stl?
Вот список методов std::vector(итераторы опущу):
Матёрые разработчики на C++ скажут «И чего тебе ещё надо?». Прям надо-надо? Этого хватит. Чтобы было удобно? Этот список — считай ничего нет.
Я большую часть времени пишу на других языках. Какое-то время писал на PHP, сейчас пишу на js/ts. Почему у этих языков порог входа кардинально отличается? Ладно, js — понятно. Там статического анализа вообще. Но ts… Те же типы, те же проверки. Да, согласен, все сильно мягче и легко обойти систему типов, но все же. Я не очень знаком с другими языками, поэтому мои сравнения можете провести и с другим, знакомым вам, языком программирования.
Почему это сравнение имеет место быть? Я упоминал про порог входа и позже я к этому вернусь. Это тесно связано, но даже если не брать в расчёт порог входа, а взять просто то что удобно использовать мне, как разработчику, в своей работе. Js/ts предлагает (все тот же пример с vector-ом) из коробки кучу методов для работы с массивами. И половиной (как минимум третью) я пользуюсь в работе интенсивно. Посмотрите документацию по массивам в javascript-е. Посмотрите документацию по массивам в PHP. Как много методов для работы с массивом… Все тем же самым вектором с другим названием. Почему в стандартной библиотеке этого всего нет? Она же стандартная, там должны быть вещи, которые нужны в работе ежедневно. Взять хотя бы тот-же splice. В js-е (насчёт PHP тут уже не знаю) есть и библиотеки, которые предоставляют методы по работе с массивом. Взять тот же lodash. Многие вещи перекочевали из него в стандарт языка. Что у C++? Boost? Там методов по работе с вектором примерно столько же. Почему в 2-х крупных (одна из которых стандартная) библиотеках там мало возможностей по работе с самой простой структурой — вектором.
Ещё одно замечание в сторону stl. Это же стандартная библиотека, ей пользуется куча разработчиков. Почему она работает медленно, а, в некоторых случаях, крайне медленно(iostream). Я, удовольствия ради, пишу библиотеку компонентов, контейнеров и прочих полезных вещей на C++, aka boost. Как так вышло, что моя реализация vector-а работает примерно на 35% быстрее. Это не маленькие цифры (Библиотека сыровата и тесты проводились на одном конкретном методе, но сомневаюсь, что остальные методы покажут другие цифры). Если взглянуть на код stl — становится страшно. Это, конечно, не моя проблема, не мне поддерживать его, но все же. Много умных людей занимаются поддержкой stl, но код выглядит так-себе, нагромождено и избыточно, на мой взгляд (сугубо личный взгляд). Производительность меньше чем у сторонней реализации, хотя те ребята должны знать язык очень хорошо, а значит его особенности и способы оптимизации. Да ещё и для работы с классом ничего нет. Я уточню, vector не единственный к чему можно придраться. Взять любой другой, как минимум контейнер, и будет все то-же самое.
C++ считается сложным языком с высоким порогом входа, а разработка на C++, обычно, многословнее и медленнее (в сравнении с js, PHP, python etc.). Почему так? Что такого сложного в C++? Может я не прав, но самое сложное — понять как работают указатели, не забывать подчищать за собой память и проверять что указатель не nullptr. Если ты все это делаешь, сложностей быть не должно, по крайней мере серьезных. Так почему C++, обычный язык, имеет такой высокий порог входа?
Давайте представим, что мы пишем на typescipt-е (без асинхронщины). Напишем функцию main (для большего сходства) и сделаем что-нибудь простое. Поработаем с массивами, со строками и с чем нибудь ещё. Теперь возьмите вот этот код, перепишите типы и объявления переменных в стиле C++, так чтобы это был валидный C++ код. Что будет, если подключить библиотеку реализующую массив (vector) и строки с API как в javascript-е. Предполагаю оно скомпилируется и, скорее всего, будет работать. Да, код придется сильно поправить, но ни строчки не прибавится (не считая include-ов). Так на самом ли деле C++ такой сложный? Разве он на столько многословен? Почему порог вхождения в ts существенно ниже чем в C++?
Возможно я не прав, напишите в комментариях, но если бы в C++ были более обширные стандартные инструменты, он был бы проще. Да, работая с указателями придётся и это будет уже не так тривиально, но в большей степени он был бы проще. Так почему в стандарте, где сидит куча умных людей программистов, поставщиков компиляторов, представителей крупных компаний и т.д., нет таких простых вещей? Велика вероятность, что если бы на C++ было бы проще писать, он был бы доступен большему кругу людей и большим сферам, там где его не используют, потому что он сложный, а им не надо быстро. Можно было бы использовать все это для обучения, а потом углубляться в дебри указателей, памяти, ссылок и т.д. и т.п.
Неполнота stl
На дворе 2020 год. Только-только вышел новый стандарт. Добавили кучу полезностей (Подробный список можно посмотреть здесь, а также в других статьях на хабре). Чего только нет в современном stl для базовых ситуаций. Многие все ещё ждут networking, мелочи, но все равно не очень понятно в чем проблема. Если взглянуть на boost, там есть и networking и ещё много всего, но проблема, к которой я веду, присутствует и там.
Так в чем же проблема? А проблема в том, что если взглянуть на документацию stl к какому-нибудь vector, то что там можно увидеть? Несколько методов да и только? Я не беру в расчёт перегруженные операторы и методы типа data и at. Итак, что у нас есть:
erase — безусловно нужный метод. Удаление элемента. Все ок, кроме… Почему erase? Почему не remove или delete? Это распространённая практика во многих языка. Это было бы очевиднее людям, которые приходят в C++ из других языков. Ладно, не буду придираться к названиям, хотя методы push_back и pop_back мне все же немного странно видеть. Зачем это лишнее back?
Ладно. Придрался к названиям. Разве это и есть неполнота stl?
Вот список методов std::vector(итераторы опущу):
- at, operator[], front, back, data — это методы для доступа к данным
- begin, end, rbegin, rend — итераторы. Тут комментариев не будет
- empty, size, max_size, reserve, capacity, shrink_to_fit — Все про вместимость. Большая часть методов специфична для C++ (из-за возможности работы с памятью). Тут тоже комментариев нет
- clear, insert, emplace (представить не могу зачем это, но возможно кто-то этим все-же пользуется), erase, push_back, emplace_back, pop_back, resize, swap — И это все как мы можем работать с элементами в векторе. Больше ничего нет
Матёрые разработчики на C++ скажут «И чего тебе ещё надо?». Прям надо-надо? Этого хватит. Чтобы было удобно? Этот список — считай ничего нет.
Я большую часть времени пишу на других языках. Какое-то время писал на PHP, сейчас пишу на js/ts. Почему у этих языков порог входа кардинально отличается? Ладно, js — понятно. Там статического анализа вообще. Но ts… Те же типы, те же проверки. Да, согласен, все сильно мягче и легко обойти систему типов, но все же. Я не очень знаком с другими языками, поэтому мои сравнения можете провести и с другим, знакомым вам, языком программирования.
Почему это сравнение имеет место быть? Я упоминал про порог входа и позже я к этому вернусь. Это тесно связано, но даже если не брать в расчёт порог входа, а взять просто то что удобно использовать мне, как разработчику, в своей работе. Js/ts предлагает (все тот же пример с vector-ом) из коробки кучу методов для работы с массивами. И половиной (как минимум третью) я пользуюсь в работе интенсивно. Посмотрите документацию по массивам в javascript-е. Посмотрите документацию по массивам в PHP. Как много методов для работы с массивом… Все тем же самым вектором с другим названием. Почему в стандартной библиотеке этого всего нет? Она же стандартная, там должны быть вещи, которые нужны в работе ежедневно. Взять хотя бы тот-же splice. В js-е (насчёт PHP тут уже не знаю) есть и библиотеки, которые предоставляют методы по работе с массивом. Взять тот же lodash. Многие вещи перекочевали из него в стандарт языка. Что у C++? Boost? Там методов по работе с вектором примерно столько же. Почему в 2-х крупных (одна из которых стандартная) библиотеках там мало возможностей по работе с самой простой структурой — вектором.
Ещё одно замечание в сторону stl. Это же стандартная библиотека, ей пользуется куча разработчиков. Почему она работает медленно, а, в некоторых случаях, крайне медленно(iostream). Я, удовольствия ради, пишу библиотеку компонентов, контейнеров и прочих полезных вещей на C++, aka boost. Как так вышло, что моя реализация vector-а работает примерно на 35% быстрее. Это не маленькие цифры (Библиотека сыровата и тесты проводились на одном конкретном методе, но сомневаюсь, что остальные методы покажут другие цифры). Если взглянуть на код stl — становится страшно. Это, конечно, не моя проблема, не мне поддерживать его, но все же. Много умных людей занимаются поддержкой stl, но код выглядит так-себе, нагромождено и избыточно, на мой взгляд (сугубо личный взгляд). Производительность меньше чем у сторонней реализации, хотя те ребята должны знать язык очень хорошо, а значит его особенности и способы оптимизации. Да ещё и для работы с классом ничего нет. Я уточню, vector не единственный к чему можно придраться. Взять любой другой, как минимум контейнер, и будет все то-же самое.
«Высокий» порог входа и сложность языка
C++ считается сложным языком с высоким порогом входа, а разработка на C++, обычно, многословнее и медленнее (в сравнении с js, PHP, python etc.). Почему так? Что такого сложного в C++? Может я не прав, но самое сложное — понять как работают указатели, не забывать подчищать за собой память и проверять что указатель не nullptr. Если ты все это делаешь, сложностей быть не должно, по крайней мере серьезных. Так почему C++, обычный язык, имеет такой высокий порог входа?
Давайте представим, что мы пишем на typescipt-е (без асинхронщины). Напишем функцию main (для большего сходства) и сделаем что-нибудь простое. Поработаем с массивами, со строками и с чем нибудь ещё. Теперь возьмите вот этот код, перепишите типы и объявления переменных в стиле C++, так чтобы это был валидный C++ код. Что будет, если подключить библиотеку реализующую массив (vector) и строки с API как в javascript-е. Предполагаю оно скомпилируется и, скорее всего, будет работать. Да, код придется сильно поправить, но ни строчки не прибавится (не считая include-ов). Так на самом ли деле C++ такой сложный? Разве он на столько многословен? Почему порог вхождения в ts существенно ниже чем в C++?
К чему же я все это
Возможно я не прав, напишите в комментариях, но если бы в C++ были более обширные стандартные инструменты, он был бы проще. Да, работая с указателями придётся и это будет уже не так тривиально, но в большей степени он был бы проще. Так почему в стандарте, где сидит куча умных людей программистов, поставщиков компиляторов, представителей крупных компаний и т.д., нет таких простых вещей? Велика вероятность, что если бы на C++ было бы проще писать, он был бы доступен большему кругу людей и большим сферам, там где его не используют, потому что он сложный, а им не надо быстро. Можно было бы использовать все это для обучения, а потом углубляться в дебри указателей, памяти, ссылок и т.д. и т.п.