У меня за последний год сложилось ощущение, что в стандартную библиотеку C++ хотят/пытаются внести слишком много функционала.
Был сделан выбор в пользу современных тенденций и требований рынка. C#, Java, Python умеют очень многое из коробки и людям это нравится по мнигим причинам, например:
В некоторых компаниях запрещены библиотеки кроме стандартной (нужен variant/flat_set/shared_library? Пиши сам с нуля, в компании <имя практически любой ООО работающей с деньгами> спец требования к безопасности.)
Когда пишешь что-то с чем раньше не встречался, хочется использовать что-то идущее вместе с языком, а не выбирать пару дней из N библиотек.
Документации на стандартную библиотеку всегда больше чем на сторонние.
Java, project Jigsaw. С точностью до наоборот — распиливание стандартного рантайма на несколько кусков поменьше, для тех кому не надо всё.
Также, никто не тянет Spring, Hibernate, Entity Framework в стандартные библиотеки.
По поводу документации — гораздо легче воспринимать маленькие самодостаточные компоненты.
одна реализация в одном месте вместо кучи независимых под каждый компилятор
Одна реализация — это адище для разработчика библиотеки и медленное внесение исправлений под ошибки компиляторов. Посмотрите на количество #ifdef/#elif в коде Boost для каких-либо старых компонент… а ведь это при том, что Boost недавно отказался поддерживать некоторые античные компиляторы.
Зато для пользователей библиотеки адищем является целая пачка её разновидностей. А большое кол-во директив условной компиляции — следствие зоопарка компиляторов в прошлом.
>> Lifetimes начисто противоречат как минимум copy by default в C++
> Не вижу противоречий. Поясни?
Может, не совсем правильно выразил свою мысль. Попробую написать более развёрнуто.
Во-первых, тот самый copy by default. В С++ «первичны» именно байтики, составляющие значение, а не само значение, с его семантикой и смысловой нагрузкой. Выражается это в том, что без дополнительных телодвижений значение любого типа будет банально копироваться. Делая «умный указатель», надо не забыть в обязательном порядке или запретить копирование, или правильно его обработать. Как следствие — можно схлопотать implicit copy, после чего дважды уничтожение одного и того же значения. Напротив, в Rust происходит move by default. Т.е. хочешь сделать копию — явно опиши как, а если не нужно — не будет лишних ошибок.
Во-вторых, значения «после перемещения» — т.е. значения, из которых полезную информацию переместили. Но какой-то мусор остался. И этот мусор должен быть корректно обработан деструктором.
В-третьих, тот самый borrowing. А конкретно его сложные случаи, когда заимствованная ссылка попадает внутрь структуры. В Rust в таком случае лайфтайм должен быть явно указан в типе структуры. В С++ как разрешать подобный случай — непонятно.
В-четвёртых, тонны старого кода, который про такие штуки ничего не знает. Считать отсутствие аннотаций ошибкой? Пропускать? Сделать аннотацию «не проверять аннотации»?
В общем, чисто теоретически можно написать для С++ стороннюю утилиту, которая будет выполнять проверки на время жизни. Но геморроя будет слишком много. Просто потому, что система типов С++ проектировалась на максимальную совместимость с С, а значит значения (как я писал выше) там рассматриваются скорее как пачки байт. Как результат — низкоуровневые уши торчат наружу. В то же время в Rust семантика значения первична на уровне с его представлением.
>> к тому же придётся мучительно аннотировать весь код чтобы это работало
> Не мучительнее, чем в Rust.
Компилятор обругает за каждое пропущенное место. Как поступать с пропусками аннотаций в С++ — неясно.
>> Препроцессор останется с нами навсегда во имя совместимости.
> Пусть остаётся. Но пользоваться им будет не обязательно.
Макро-константы. Их валом до сих пор.
>> Аналога же Cargo вообще не предвидится в обозримом будущем.
> Вот уж совсем не проблема языка C++. Cargo не требует стандартизации даже.
Верно. Однако IDE вы, например, хотите. Как инструмент, конечно. Стандартизировать IDE нет никакого смысла. Но почему тогда C++ — фактически единственный язык без вменяемого тулчейна для сборки и доставки зависимостей? Хотя бы как стандарта де-факто?
>> несоместимость С++ ни с кем кроме С++. Такой себе Language lock-in.
> Это утверждение справедливо для любого другого языка программирования.
В принципе да. Конкретно этот мой аргумент наверное несостоятелен. Генератора биндингов из Python в Ruby я не видел :)
>> единственное КМК что держит С++ на плаву — огромное сообщество и гигатонны уже написанного кода
> C++ на данный момент — единственный инструмент, который позволяет эффективно писать производительный код, и причина вовсе не в legacy.
Не совсем. Если не нужно жёсткое «байтоложество», то тот же Golang вполне подходит, несмотря на свой минимализм.
Короче, в С++ накопилось слишком много проблем, часть из них не имеют адекватного решения без поломки обратной совместимости.
Я бы очень даже за. Даже всерьёз начал переделывать один микросервис, просто посмотреть как пойдёт. Остановили генерация биндингов (непонятно что делать с кучей констант, заданных макросами; автора макро-констант убить мало) и zeroing drops — т.е. объект с деструктором распухает, а мне это сильно мешало делать обёртки над хендлами.
Не добавят. Lifetimes начисто противоречат как минимум copy by default в C++, к тому же придётся мучительно аннотировать весь код чтобы это работало. Концепты в Rust есть уже сейчас в виде Traits & Trait impls. Модули добавят хорошо если к 20-му году. Препроцессор останется с нами навсегда во имя совместимости. Аналога же Cargo вообще не предвидится в обозримом будущем.
Короче, единственное КМК что держит С++ на плаву — огромное сообщество и гигатонны уже написанного кода. Плюс несоместимость С++ ни с кем кроме С++. Такой себе Language lock-in.
Для сравнения.
Xiaomi Mi3
родная прошивка на 4.4 — примерно 650-700Мб
родная прошивка на 6.0 — примерно 700Мб
CyanogenMod 13 (Android 6.0) — примерно 300Мб
размеры приведены для архива с прошивкой, с учётом сжатия на флешке будет примерно вдвое больше
Как резюме — большие вопросы к Самсунгу, что их кодеры туда понапихали
Толщина кода для инита контекста рисования величина б/м постоянная, или по крайней мере всегда отличная от нуля. Дело, думаю, в этом. Как там дела в современном OpenGL — не в курсе, смотрел только мельком.
Vulkan судя по виду и не предназначен для рукопашного кодирования каждый раз. Это скорее «графический ассемблер», как когда-то называли OpenGL. Хотя в такой ситуации OpenGL переходит в лигу «графического Си».
Мне кажется, посыл статьи не в том, кто каким флагом машет, а в том, что у поставщиков контента появляется неслабый рычаг «этому плагин даю, этому не даю». Например, лиса и хром получают каждый такой плагин от нетфликса. А потом гугл даёт нетфликсу много денег, и нетфликс отключает все плагины — кроме хрома. Хотите смотреть нетфликс — запускайте хром. Насколько это соответствует реальности — я не знаю, для этого надо смотреть спеку EME.
В лисичке, кстати, проприетарные плагины можно ставить. Более того, они там есть.
К сожалению, именно эта маааленькая особенность превращает использование Gerrit в акт мазохизма, по крайней мере для меня. Настройка локальной копии требует подстановки хука для задания Commit ID, что само по себе немного. Но вот каждый новый чейнджсет превращается в:
— сделать rebase+squash
— обновления делать исключительно amend
— в качестве назначения использовать фиктивный ref, о котором надо помнить
— когда приходит добрый сосед и мержится, надо ручками опять делать ребэйз
Короче, мне это сильно напоминает старые добрые времена SVN по количеству рукопашной работы.
Попробую перечислить конкретно то, что раздражало меня. Телеметрию и т.п. не беру, слишком субъективно
1. Обновления ставятся когда МСу удобно, а не мне. Лечится правкой в реестре. Пока что.
2. Пачка лично мне не нужных приложений типа OneNote, Cortana, которые или не выпиливаются вообще, или радостно возвращаются после первого же апдейта. Даже если выпилить весь пакет вместе с ярлыком с помощью PowerShell
3. Пачка «системных» сервисов типа Content Delivery Manager, которые тоже не поддаются никакому управлению, включаются в произвольное время (что само по себе не проблема) и адски выжирают CPU и память. Рекомый CDM у меня так себя и вёл.
Ну и ещё какие-то мелочи, из разряда «проблемы индейцев шерифа не волнуют».
Плюс Win 10 по-прежнему имеет тенденцию жрать место на диске за счёт WinSxS. Сделать к нему нормальный dependency management МС в своё время не удосужились.
До 7-ки включительно windows была удобна и простому пользователю, и продвинутому. Начиная с 8-ки возможности продвинутой настройки стали усиленно прятать или перетряхивать, «оказуаливая» систему. 10-ка просто стала финальной точкой в этом процессе. Т.е. 10-ка — хорошая, наверное, система для офисных ПК. Может для геймеров. Но для тех, кто привык контроллировать поведение своего ПК она стала занозой в заднице. Именно из-за политики «большому дяде лучше знать». Я, помнится, обновился ещё в августе прошлого года, в самом начале щедрого предложения. А уже в начале октября с матюгами пересел на Linux Mint. Просто понял, что систему я больше не контроллирую никак. И любые попытки такого контроля с моей стороны будут выпилены следующим же апдейтом.
Rust
Там собсно сделали отслеживание владения и алиасинга компилятором. От зацикленных умных указателей конечно не спасает на 100%, но ногу себе отстрелить гораздо труднее.
Мой личный опыт показывает, что это все окружающие призваны работать с С++ через C ABI. С++ не стыкуется сам по себе ни с кем кроме С и С++. Все остальные делают C-compatible FFI. А пакетный менеджер не родился КМК из-за того, что производителей компиляторов было несколько. И они в начале развития С++ не очень хорошо дружили друг с другом. Посмотрите хотя бы на «зоопарк» систем сборки. Отсюда, кстати, и отсутствие какого-то единого соглашения на структуру исходников для каждого «компонента». Другие языки появлялись усилиями какой-то одной компании или группы энтузиастов, и только потом могли появляться «форки». Либо просто выходил порт референсного компилятора/рантайма.
Как по мне, двоеточие визуально отделяет имя параметра от его типа, что есть хорошо. Если вы ссылаетесь на golang, то там для такого различения требуется немного «приморгаться».
Java, project Jigsaw. С точностью до наоборот — распиливание стандартного рантайма на несколько кусков поменьше, для тех кому не надо всё.
Также, никто не тянет Spring, Hibernate, Entity Framework в стандартные библиотеки.
По поводу документации — гораздо легче воспринимать маленькие самодостаточные компоненты.
Зато для пользователей библиотеки адищем является целая пачка её разновидностей. А большое кол-во директив условной компиляции — следствие зоопарка компиляторов в прошлом.
> Не вижу противоречий. Поясни?
Может, не совсем правильно выразил свою мысль. Попробую написать более развёрнуто.
Во-первых, тот самый copy by default. В С++ «первичны» именно байтики, составляющие значение, а не само значение, с его семантикой и смысловой нагрузкой. Выражается это в том, что без дополнительных телодвижений значение любого типа будет банально копироваться. Делая «умный указатель», надо не забыть в обязательном порядке или запретить копирование, или правильно его обработать. Как следствие — можно схлопотать implicit copy, после чего дважды уничтожение одного и того же значения. Напротив, в Rust происходит move by default. Т.е. хочешь сделать копию — явно опиши как, а если не нужно — не будет лишних ошибок.
Во-вторых, значения «после перемещения» — т.е. значения, из которых полезную информацию переместили. Но какой-то мусор остался. И этот мусор должен быть корректно обработан деструктором.
В-третьих, тот самый borrowing. А конкретно его сложные случаи, когда заимствованная ссылка попадает внутрь структуры. В Rust в таком случае лайфтайм должен быть явно указан в типе структуры. В С++ как разрешать подобный случай — непонятно.
В-четвёртых, тонны старого кода, который про такие штуки ничего не знает. Считать отсутствие аннотаций ошибкой? Пропускать? Сделать аннотацию «не проверять аннотации»?
В общем, чисто теоретически можно написать для С++ стороннюю утилиту, которая будет выполнять проверки на время жизни. Но геморроя будет слишком много. Просто потому, что система типов С++ проектировалась на максимальную совместимость с С, а значит значения (как я писал выше) там рассматриваются скорее как пачки байт. Как результат — низкоуровневые уши торчат наружу. В то же время в Rust семантика значения первична на уровне с его представлением.
>> к тому же придётся мучительно аннотировать весь код чтобы это работало
> Не мучительнее, чем в Rust.
Компилятор обругает за каждое пропущенное место. Как поступать с пропусками аннотаций в С++ — неясно.
>> Препроцессор останется с нами навсегда во имя совместимости.
> Пусть остаётся. Но пользоваться им будет не обязательно.
Макро-константы. Их валом до сих пор.
>> Аналога же Cargo вообще не предвидится в обозримом будущем.
> Вот уж совсем не проблема языка C++. Cargo не требует стандартизации даже.
Верно. Однако IDE вы, например, хотите. Как инструмент, конечно. Стандартизировать IDE нет никакого смысла. Но почему тогда C++ — фактически единственный язык без вменяемого тулчейна для сборки и доставки зависимостей? Хотя бы как стандарта де-факто?
>> несоместимость С++ ни с кем кроме С++. Такой себе Language lock-in.
> Это утверждение справедливо для любого другого языка программирования.
В принципе да. Конкретно этот мой аргумент наверное несостоятелен. Генератора биндингов из Python в Ruby я не видел :)
>> единственное КМК что держит С++ на плаву — огромное сообщество и гигатонны уже написанного кода
> C++ на данный момент — единственный инструмент, который позволяет эффективно писать производительный код, и причина вовсе не в legacy.
Не совсем. Если не нужно жёсткое «байтоложество», то тот же Golang вполне подходит, несмотря на свой минимализм.
Короче, в С++ накопилось слишком много проблем, часть из них не имеют адекватного решения без поломки обратной совместимости.
Я бы очень даже за. Даже всерьёз начал переделывать один микросервис, просто посмотреть как пойдёт. Остановили генерация биндингов (непонятно что делать с кучей констант, заданных макросами; автора макро-констант убить мало) и zeroing drops — т.е. объект с деструктором распухает, а мне это сильно мешало делать обёртки над хендлами.
Не добавят. Lifetimes начисто противоречат как минимум copy by default в C++, к тому же придётся мучительно аннотировать весь код чтобы это работало. Концепты в Rust есть уже сейчас в виде Traits & Trait impls. Модули добавят хорошо если к 20-му году. Препроцессор останется с нами навсегда во имя совместимости. Аналога же Cargo вообще не предвидится в обозримом будущем.
Короче, единственное КМК что держит С++ на плаву — огромное сообщество и гигатонны уже написанного кода. Плюс несоместимость С++ ни с кем кроме С++. Такой себе Language lock-in.
Xiaomi Mi3
родная прошивка на 4.4 — примерно 650-700Мб
родная прошивка на 6.0 — примерно 700Мб
CyanogenMod 13 (Android 6.0) — примерно 300Мб
размеры приведены для архива с прошивкой, с учётом сжатия на флешке будет примерно вдвое больше
Как резюме — большие вопросы к Самсунгу, что их кодеры туда понапихали
Получается, когда
наступит счастьеосновные вендоры реализуют поддержку Vulkan, можно будет иметь одну реализацию OpenGL поверх него?В лисичке, кстати, проприетарные плагины можно ставить. Более того, они там есть.
— сделать rebase+squash
— обновления делать исключительно amend
— в качестве назначения использовать фиктивный ref, о котором надо помнить
— когда приходит добрый сосед и мержится, надо ручками опять делать ребэйз
Короче, мне это сильно напоминает старые добрые времена SVN по количеству рукопашной работы.
Или приблуда вроде Slack Client, который по факту запускает WebKit?
1. Обновления ставятся когда МСу удобно, а не мне. Лечится правкой в реестре. Пока что.
2. Пачка лично мне не нужных приложений типа OneNote, Cortana, которые или не выпиливаются вообще, или радостно возвращаются после первого же апдейта. Даже если выпилить весь пакет вместе с ярлыком с помощью PowerShell
3. Пачка «системных» сервисов типа Content Delivery Manager, которые тоже не поддаются никакому управлению, включаются в произвольное время (что само по себе не проблема) и адски выжирают CPU и память. Рекомый CDM у меня так себя и вёл.
Ну и ещё какие-то мелочи, из разряда «проблемы индейцев шерифа не волнуют».
Плюс Win 10 по-прежнему имеет тенденцию жрать место на диске за счёт WinSxS. Сделать к нему нормальный dependency management МС в своё время не удосужились.
Там собсно сделали отслеживание владения и алиасинга компилятором. От зацикленных умных указателей конечно не спасает на 100%, но ногу себе отстрелить гораздо труднее.