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


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

А Бьярне оптимист :) вроде даже в рассылку комитета скидывали тесты что если в 2-4 раза это прям ну очень хорошо, а на практике стоит ожидать примерно 40% на ровном месте.
Да и вообще многие докладчики говорили что модули это не про скорость компиляции, ускорение это просто побочный эффект.
www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1441r1.pdf

Блин, в моих проектах даже 40% это будет хорошо, не говоря уже о 2-4 раз.

Существует группа, которая занимается неопределенным поведением. Фактически, они работают над тем, чтобы хорошо определить неопределенное поведение: чтобы мы знали, что такое неопределенное поведение и почему оно таковым становится.

Кому интересно, вот как выглядит черновик с перечислением того что нашли по UB в стандарте (естественно не полный!):
www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1705r0.html

Там есть довольно странные вещи, вроде того что вот такое это UB.
char data[10];
char* p = data + 10; // Вот эта строчка сама по себе UB.


Я думаю даже те кто писал стандарт имели ввиду что UB это именно то КУДА указывает результат, а не сама операция '+'.

нет, эта строчка не UB, потому что формировать указатель на N+1-й элемент массива можно, это нужно для end итераторов. А в общем случае нельзя именно формировать указатель за пределы массива.

Ну да, + 11.
Но это сути особо не меняет. Главное что сама операция сложения является UB, понятно что она на мусор какой-то указывает, но сама операция то тут причем? Яб ещё понял что UB результат который окажется в p, но что само сложение UB это уже за гранью.

А что не так? Никто не обещал, что сложение указателя это какая то тривиальная операция, которая всегда определена. Тоже самое можно сказать про сложение знаковых чисел. При переполнении имеем UB.

Я не знаю в какой вселенной это не тривиальная операция, но в этой эта операция выглядит примерно как (char*)(size_t(data) + 11X), где Х это константа времени комптляции. Т.е это просто сложение двух чисел, к тому же сами адреса неотрицательные, так что числа эти беззнаковые. Каких либо причин делать эту операцию UB я не вижу.

Кажется, вот в этом ответе вы увидите пример где арифметика указателей это не «просто сложение двух чисел».

Вообще чтобы понять логику с++ надо мыслить в категориях очень абстрактного вычислительного устройства в вакууме.
Некоторые разработчики компиляторов утверждали, что неопределенный порядок давал более быстрый код. Это было неправдой, так что на лицо прогресс.

Интересно всё-таки, как он получил, что "неправда". Смысл оптимизации тут безусловен, вопрос в том, сколько же реально на этом можно выиграть в типовом (и не очень) случае...


Как по мне, всё это должно управляться стандартизованными опциями на уровне синтаксических контекстов. Ставим, например, умолчание на строгое вычисление аргументов функций слева направо… где кому не хватит скорости — разрешит именно эту оптимизацию на функцию или блок. Да, 99% кода не в "critical path" не потребуют особого внимания, а 1% можно и отработать с учётом всей специфики.

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

Так то я за предопределенный порядок.
В critical path вы как раз хотите, чтобы исполнялось ровно то, что написано, а не а-бы что, основанное на эвристиках компилятора,

Абсолютно некорректное замечание (и не надо решать за меня, чего я хочу). В critical path — по скорости, разумеется — меня будет интересовать максимум оптимизаций, которые я ему позволю, но дальше я уже буду считать, что компилятор корректен в тех пределах, которые ему таки были дозволены. Если он что-то сделает неправильно, это должно быть видно по результату, а не по "ассемблерному листингу", который может быть ещё и нечитаемый из-за объёма и путаности, и ещё и который для выполнения ваших условий надо, вероятно, перечитывать на каждой компиляции?


"Абы что" не должно быть, пока компилятор выполняет главное условие — корректность всех применённых преобразований (случай багов в компиляторе пропустим). А вот какие они в каких пределах — я как раз хочу определять своими средствами. То же пресловутое переполнение в целочисленных операциях — да, я хочу, чтобы умолчанием была генерация ошибки (вылет исключения и т.п.), но если я найду, что для какого-то участка кода я уверен в непереполнениях (причём не только для знаковых! эта неровность правил C/C++ — тупой рудимент древности) — я ставлю ему разрешение и получаю, например, +10% скорости в нём. То же с порядком аргументов (может дать сокращение необходимых вычислений), с побочными эффектами (да пусть пишут i++ * i++, если им так легко читать) и прочая и прочая.


И не надо НЛПить в стиле 90-х, это давно не работает.

Бьярне: Этот вопрос касается большого и сложного дела. Не думаю, что в C++ есть какая-либо основополагающая функция, которую мы могли бы удалить, не разозлив несколько сотен тысяч или даже миллион пользователей. Такого не должно произойти
в теории существует способ удаления старых функций — эпохи. Предположим, выходят они вместе с версией языка с++26, после чего считаем, что весь код до эпох — с++23, а для более нового можно явно разметить версию языка на уровне модулей. И потом уже линковать эти модули, собранные разными версиями языка, воедино. Если удастся обойти поломки ABI, то так можно запрещать старые фичи, не ломая их у клиентов со старыми кодобазами.
Я не видел в этом языке (Rust) ни одной функции, которую я бы очень хотел добавить в C++. Некоторые вещи нельзя просто включить в язык
тут немного странная позиция у Бьярне. Кажется, правильнее было бы сказать что многие фичи rust нельзя просто взять и добавить в с++, а уже среди оставшихся мало чего стоит добавлять.
Мне не нравится, когда его называют AST (Abstract Syntax Tree) потому, что это не синтаксис, не абстрактный и не древо. Но люди все называют это таким образом.
насколько я понял, abstract относится к syntax, а не к tree, т.е. «дерево абстрактного синтаксиса». И кажется, этот термин появился чуть раньше.
Ну там и не говорится что дерево абстрактое, как раз к синтаксису это и онтносится
Не знаю про то это, или нет, но есть у нас один проект, который написан за ~15 лет на питоне 2. Выглядит соответствующе, кодовая база… приличная. Вообще говоря, в трекере уже несколько лет висит таска «давайте двигаться в сторону питона 3», исполняется она примерно никак. Понятное дело что там проблемы аборигенов, времени тупо не сильно много, и, сделать волевое движение, написать роадмап (который будет тоже многолетним, и бизнесу никуда не уперся), структурировать подход, етк… Но подозреваю что мы не одни такие, и полторы компании на рынке начнут работать «правильно». С другой стороны я пару лет уже как в swift, а тут считается нормальным ломать обратную совместимость, потому что кому-то «захотелось» (https://github.com/apple/swift-evolution/blob/master/proposals/0004-remove-pre-post-inc-decrement.md) как самый яркий пример кмк. Что тоже вызывает БОЛЬ.

Ну мы этот переход Py2->Py3 прошли. Да, в отделе 5-10 человек и как не самая главная задача (ресурсы выделялись чуть больше, чем по остаточному принципу, но меньше, как для существенной задачи) — заняло в таком режиме считай 2 года: в конце лета 18-го был поднят вопрос "давайте таки что-то делать", и на сейчас мы состоянии "по умолчанию всё на Py3, но совместимость с Py2 будем отменять только в январе".
Путь — всё через six (увы, прямее не нашлось).
Вообще скорость выполнения больше зависит от скорости проворота по цепочке до конечного клиента с обратной связью, чем наоборот. У нас получалось, что было два характерных оборота по 9-10 месяцев (фактически, интервал между LTS релизами) — первый до "код запускается под обоими, но никому Py3 не включаем", второй до "по умолчанию таки Py3, но готовы откатиться в любой момент".

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

Да, именно так. Сколько было нападок на Rust за его синтаксис (типа fn foo<'a, T>(a: &'a [T], b: T) -> T + 'a), но как выяснилось даже такой крутой инженер как Бьярн не смог придумать лучше. Соотвественно, невозможен точный анализ, только эвристические анализаторы для анализа времён жизни объектов.

Ты ничего не понял. Он это про заимствование и «линейную логику». См. абзац выше.

Так то у Раста 2 проблемы [минимум].

Я так и понял, заимствование = borrowing в терминах Rust. Что не так?

Синтаксис тут ни при чем, это несвязанная тема.

Кстати, заимствование и лайфтайм тоже хоть и связаны, но не одно и то же.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.
Информация
Дата основания

25 марта 2012

Местоположение

Россия

Сайт

jugru.org

Численность

51–100 человек

Дата регистрации

22 августа 2013

Блог на Хабре