Как стать автором
Обновить

Комментарии 147

И сегодня как назло сломался сертификат для https://wg21.link/ . Ответственные предупреждены, скоро починят и ссылки на предложения заработают.

Антон, а ты упомянул, что у вас используется свой аналог std::expected, а можно поделиться кодом?

Почему нет ни слова о Reflection?

"А значит, только года через три мы увидим следующие идеи:

...

Reflection;

..."

Увы, слово есть...

А значит, только года через три мы увидим следующие идеи:

  • Получение stacktrace из исключений;

  • Networking;

  • Reflection;

  • Полноценная библиотека для работы с корутинами.

А с учётом того, что ещё есть лаг на реализацию + лаг на обновление тулчейнов, использовать это все получится только в 2028-2029 не раньше :) В общем, только наши внуки смогут отправить байтик по сети стандартным способом :)

Вот собственно практически всё, что нужно уже позавчера, откладывают на завтра.

Все эти ожидания «когда подвезут» напоминает анекдот про растения:
«Скорей бы эти пчелы прилетели»
  • Networking;

  • Reflection;

А может и не увидим ¯\_(ツ)_/¯

for (const auto& val : {'Hello', 'world'} | std::views::join_with(", "))     std::cout << val;  // Выводит Hello, world  

А точно ли тут нужен for, для банальной вещи как join?

Так for тут только для вывода.

Не очень понял, какого типа тут val что для вывода нужен for

Тип будет const char*

Фактически будем итерироваться по диапазону {"Hello", ", ", "world"}

Круто, конечно, но немного упущена идея почему в питоне это проще :) и на который ссылаются в данном примере

Ааа, т.е. join на самом деле не соединяет элементы контейнера? Может тогда лучше было назвать это interleave_with()?

std::views ленивые и не делают промежуточных контейнеров. Так что и std::views::chunk, и std::views::zip, и std::views::take лишь ловко оперируют указателями и возвращают вам ссылки на нужные элементы в нужный момент.

Подождите, а какой магией мне
const std::string helloWorld = join_something() получить-то?

Вот так:

const auto helloWorld = container
    | std::views::join_with(", ")
    | std::ranges::to<std::string>()
  ;
Actually, nice. Достаточно лаконично и вместе с тем всё еще сохраняет смысл, чтобы уже начинать использовать ЭТО а не велосипедный JoinVector() который есть в каждом среднем проекте :)
Лаконично… если бы не этот оператор. Давно на C++ не программировал и этот оператор прям глаза режет, ну я как понимаю его ещё в C++20 ввели

Маздайщик что-ли? Для подобных есть паскалик, бейсик, там авось си с классами.

Т.е. мало то, что "оператор глаза режет" в C++ - это уже смешно. А уж чтобы пайп резал. Это явно заоблачный полёт.

Действительно смешно...использование оператора, который

а)не интуинтивно понятен

б)имеел уже другое предназначение

ЭТО смешно.

Мне режет не сам оператор глаза, а его использование тут и в других подобных методах

Тут надо бы новый оператор, допустим как в fsharp |>

а)не интуинтивно понятен

Кому? Маздайщикам? Это максимально понятно тем, кто занимается и с цпп и снормальными ос.

б)имеел уже другое предназначение

Где имел? Когда?

ЭТО смешно.

Что?

Мне режет не сам оператор глаза, а его использование тут и в других подобных методах

Т.е. си с классами маздайщик? Причём тут цпп, оператор, интуитивно?

Тут надо бы новый оператор, допустим как в fsharp |>

Бездарное дерьмище. Ну в целом я не ошибся. Можно только похвалить цпп за то, что такого здесь никогда не будет. А если и будет - можно будет его(цпп) хоронить.

Амм..."битовое или" как-бы

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

Никакого отношения оператор| не имеет к "битовому или". Битовое или - это специализация оператора| для некоторых базовых типов.

Это, на самом деле, типичная проблема для людей далёких от настоящего цпп. Которые такие же куллстори рассказывают про foo(a){}и `foo(b) {}` - им так же не очевидно почему foo не имеет никакого другого "назначения".

Точно так же как нужно понять, что функцию не определяет имя. Точно так же в цпп нет никаких "битовых или" или прощей чуши. Есть операторы. Операторы могут иметь какую угодно логику. И то, что эти опираторы имеют какую-то дефолтную реализацию для каких-то дефолтных тип - это не означает, что эти операторы стали этими дефолтныи.

Аналогично в fs есть `path/to/file`, да, да с палочкой. И это не делить. А ещё есть >> << в iostream. И это не сдвиги. Как удивительно, да? Никогда такого не было.

Я в приницпе не понимаю как люди могут писать на цпп и рассуждать подобным образом. Даже если это какие-то помойные си с классами из 98года. Ведь даже там были ёлочки.

 А ещё есть >> << в iostream. 

Ну при этом, это сохраняет интуитивную понятность. То-есть, даже не знающий человек поймет что:

left << right - отправляет что-то из правой стороны в левую.

left >> right же наоборот

Любому кто видел командную строку юникс или Powershell пайп вида `cat x | grep y` точно так же понятен.

Это оправдания, которые не имеют смысла. Не говоря уже о том, что куда-то потерялось "другое назначение"? Ах да, это другое.

Ну это нормально, когда маздайщик не понимающий то, чем является цпп - начинает жаловаться на что-то. Возможно просто ретранслирует какие-то лозунги. А т.к. это пустой трёп, то он не учитывает то, что уже есть и вообще не имеет какой-то связи с реальностью.

Поэтому, когда подобный эксперт заходит в тупик в своих рассуждениях - начинаются манёвры. Вот так бам и забыть для >> про:

б)имеел уже другое предназначение

Ну имел и имел. Какая разница, да?

Такая же история с "знающий человек", который не знает про пайпы.

Действительно смешно...использование оператора, который 

а)не интуинтивно понятен

так ведь по аналогии с pipe оператором в bash'е...

Это как std::quoted, вроде и есть, а как использовать, непонятно

Большое спасибо за статью. Конечно читать про все эти новинки здесь гораздо проще, чем постоянно мониторить cppreference или тот же реддит.

Подскажите пожалуйста, я видел несколько интересных предложений от Герба Саттера на тему операторов as/is p2392 / (видео) и модификаторов аргументов функций in out inout move (видео) / рандомный пример кода

А есть какая-то информация о том, в каком они статусе, и к какой версии стандарта их ждать, либо до какой их точно не ждать?

Предложение на as/is было встречено положительно, но в C++23 pattern matching уже не попадёт. Моё предчувствие - идея пройдёт в стандарт C++26. А за прогрессом идеи можно наблюдать тут https://github.com/cplusplus/papers/issues/1064

А по второй идее предложение ещё не рассматривали. Но мне кажется, что шансы на принятие - минимальны

Удивлёе, что всем нравится as/is. По-моему с ним очень легко получать не то, что ты ожидаешь. Даже сам Herb набагал в слайдах, потому что думал, что is работает так, как логично, а не так, как он в реальности может работать

Подробнее тут писал:

PS: И в комменты на реддит не пришёл он похоже, как в блоге обещал

Нравится потому что понятнее чем альтернативы:

  inspect (shape) {
    (as<Circle>    ? [r])   : return 3.14 * r * r;
    (as<Rectangle> ? [w, h]): return w * h;
  } 

Хотя, на мой взгляд, с as/is тоже не идельно:

inspect (shape) {
  [r]   as Circle    => 3.14 * r * r;
  [w,h] as Rectangle => w * h;
}

Против синтаксиса я ничего не имею, более того, считаю второй более человечным.

Напрягает именно семантика того, как определяется разваливается в то, что просят или нет. Чтобы не было кейсов, когда что-то является int, но не является integral, например

В C++23 добавляется класс std::expected
Добавляется, похоже, в сломанном виде.
Ну ок, еще один std::regex.

Хранить вторым аргументом исключение - это должно быть редким кейсом. Упор в std::expected сделан на хранение кодов ошибки - вы так получите тривиальность копирования expected, меньший размер объекта, более быструю передачу через регистры и т.п.

А вот кидать код ошибки - это очень сомнительное удовольствие, лучше уж кинуть что-то отнаследованное от std::exception, а именно bad_expected_access. Ну и ловить в коде тогда можно весьма ожидаемый std::exception, а например не srd::errc.

Что же касается operator* - в дебаге там будет assert, который поможет вам поймать проблему в тестах. В C++ operator* всегда является небезопасным доступом, и программист в ответе за проверку. Хотите чтобы стандартная библиотека делала проверку за вас - используйте value(). Если менять устоявшееся правило только для одного класса то будет только хуже - возникнет путанница.

Ну и наконец, это же C++. Не нравится стандартный std::expected - напишите и используйте свой, никто не заставляет пользоваться тем, что не подходит под ваши конкретные нужды.

Хранить вторым аргументом исключение — это должно быть редким кейсом
Это было основным кейсом.
Упор в std::expected сделан на хранение кодов ошибки
У меня есть некоторые сомнения в целесообразности упоров на коды ошибок в стандартной библиотеке, в целом построенной вокруг исключений.
вы так получите тривиальность копирования expected
Тривиальность копирования как бы зависит не только от E, но и от T.
кидать код ошибки — это очень сомнительное удовольствие
С этим невозможно не согласиться. Если ими не пользоваться, то и кидать их не придется.
Если менять устоявшееся правило только для одного класса то будет только хуже
Если рассматривать expected просто как advanced optional — несомненно. Проблема в том, что это был не совсем advanced optional.
Не нравится стандартный std::expected — напишите и используйте свой
О чем и речь.

Это было основным кейсом у Александреску. Однако большинство людей в комитете весьма обоснованно решили, что:

  • кидать int/enum -- жуть и будет проскакивать мимо всех пользовательских catch(const std::exception& e)

  • обязывать пользователей всегда хранить тип, отнаследованный от std::exception -- повлияет на производительность std::expected, из-за vptr+код+флаг он перестанет влезать в регистры для возврата и компилятор начнёт возвращать его через стек

Если вы видите рабочий выход из этой ситуации -- предлагайте рабочее решение, отправим его замечанием к C++23 от России.

кидать int/enum — жуть
Жуть. Не используйте int/enum в качестве исключений.
обязывать пользователей всегда хранить тип, отнаследованный от std::exception — повлияет на производительность
Стандарт вроде бы нигде не обязывает пользователей наследовать все исключения от std::exception, так с чего бы обязывать здесь? Пользователь как бы сам в состоянии определиться, по карману ему там std::exception или нет.
предлагайте рабочее решение
Я не очень понимаю, что тут предлагать. Изначально это был именно throw exception, но отложенный во времени и пространстве, и в этом была вся фишка. При натягивании его на коды ошибок получилось что-то совсем другое. Оно, возможно, тоже имеет право на существование и найдет применение, но фишка утеряна.

А давайте действительно пофорсим фикс через коментарий от страны. В предложении есть замечание, что возможна кастомизация выкидывания исключения, но в данный момент её не предлагают.

Завёл тикет https://github.com/cpp-ru/ideas/issues/509

Добавьте плиз в тикет примеров/мотивации/деталей/...

Ну и наконец, это же C++. Не нравится стандартный std::expected - напишите и используйте свой, никто не заставляет пользоваться тем, что не подходит под ваши конкретные нужды.

Почему комитет игнорирует гугловый Status и StatusOr, проверенные годами на продакшене классы для обработки ошибок?

В комитете есть ребята из гугла, но они не торопятся предлагать подобное, а вместо этого голосуют по предложению expected. Может Status и StatusOr не так ужи и хороши?

Status имеет намного более лучшую производительность в сравнении с этим предлагаемым интерфейсом:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r11.html#expected.expected


Для сравнения:
https://github.com/abseil/abseil-cpp/blob/master/absl/status/status.h#L658

где самые частые ошибки могут просто жить внутри младших битов uintptr_t

В стандарте прописывается интерфнйс а не реализация. Слова "exposition only" в предложении не спроста стоят. Так что ничего не запрещает оптимизацию из abseil использовать в реализации стандартной библиотеки.

А что такое «самые частые ошибки»? В expected тип ошибки параметризуемый.
Но ведь это ошибки определенной доменной области — grpc…

И опять же, в expected тип ошибки параметризуемый. Или вы предлагаете стандартизировать оптимизацию — прятать ошибку в указателях, если она может быть воткнута в N бит (где N зависит от конкретной платформы)? По-моему это чересчур специфично для general purpose класса.

Что же касается operator* - в дебаге там будет assert, который поможет вам поймать проблему в тестах. В C++ operator* всегда является небезопасным доступом, и программист в ответе за проверку. Хотите чтобы стандартная библиотека делала проверку за вас - используйте value(). Если менять устоявшееся правило только для одного класса то будет только хуже - возникнет путанница.

Почему тогда нельзя получить unsafe значение из std::variant? Почему только либо get_if либо исключение?

На operator*() никак std::variant не ложится, а std::visit покрывает большинство кейсов когда нужен непроверенный доступ. Если у вас другие кейсы и непровереный доступ вам нужен - пишите предложение для включения в стандарт, поможем с защитой идеи.

В примере везде используется std::get, который кидает исключение при попытке достать неверный тип. Замена на get_unsafe кардинально изменит поведение типа

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

Во-вторых, раньше был union и при получении не того типа был UB, но обычно перед получением значения проверялся тип с помощью is_* методов.

Вот для данного случая и пригодился бы get_unsafe().

Ок, уговорили. Если сделаете черновое предложение по инструкции - поможем с его доведением до ума и продвижением в комитете

А std::error_code вторым аргументом имеет право на жизнь?

Да, там может быть что угодно, хоть std::vector

В P0627 добавили функцию std::unreachable() для информирования компилятора о недостижимых участках кода (таких, куда программа никогда не заходит во время своего выполнения).

И что компилятор с этим будет делать? Не будет компилировать этот участок или при его достижении программа выбросит ошибку, что туда нельзя?

Что хочет, то и будет делать. Но, скорее всего, не будет компилировать этот участок, а все условия которые "ведут" в него будет считать ложными.

И что компилятор с этим будет делать?

Компилятор сможет производить дополнительные оптимизации полагаясь на то, что эта ветка кода никогда не выполнится.


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

При достижении будет UB.

Прошу простить меня за невежество, но какой вообще может быть смысл в таком операторе? Зачем писать (или оставлять) недостижимый код, а потом же помечать его недостижимым? Разве не будет лучшим вариантом вообще не писать код?

Это то же самое, что __assume(0) из MSVC, только стандартное.

Это обёртка над тем, что уже тысячи лет в нормальных компиляторах, а именно __builtin_unreachable

Тем, что он влияет на анализатор. Точно так же как и throw. https://godbolt.org/z/fshW7Wodz - максимально простой пример. Конечно, в реальности контексты использования более сложные, но суть такая же.

Т.е. мы точно знаем, что код сюда не дойдёт, но это нигде не отражено на уровне типов. Не написать код мы не можем - это будет не-полное использование и компилятор будет ругаться.

Так же в некоторых случаях компилятор просто не может вывести это из кода. Допустим из произвольного asm. Тот же noreturn применяется для того же.

Конечно, куда лучше было бы ограничить это где-то сверху и далее информацию передать через типы, но такого нет.

Предположим, что код с интами работает быстрее, а отрицательные числа нам ненужны. Заменить на uint32_t нельзя - будет медленее. Но компилятор всегда будет предполагаеть наличие их.

Поэтому можно сделать if(x < 0) __builtin_unreachable(); либо if(x >= 0) else __builtin_unreachable()

Это поможет куда лучше оптимизировать код.

А что с модуляризацией стандартной библиотеки? Про это вообще нигде не пишут.

Полноценная библиотека для работы с корутинами.
это имеется в виду std::executor? Жаль, что не прошел. Там какие-то проблемы нашли или просто не успели?

Интересно узнать, почему не завезли такие возможности.
constexpr class

static operator()

Portable assumptions - [[assume(condition)]]

#warning

Вот читал в документе, и казалося что должны добавить.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p1018r14.html#P2350r2

Все эти вещи успели проскочить нужные подгруппы и есть все шансы увидеть их в C++23

Спасибо.

А std::ranges::zip будет?

Его еще в октябре одобрили.

Интересно узнать, есть ли какие-то продвижения по контрактах?
Хотелося б иметь такое в стандарте.

Их готовятся добавлять по кусочкам в стандарт. Например на подходе [[assume(x)]]

  • std::expected — новый механизм сообщения об ошибках без использования исключений и без недостатков кодов возврата.

Хорошая штука, аналоги которой есть во многих библиотеках. Жаль только, что хотя бы без аналога оператора "?" из Rust, использовать его не так удобно. Может быть к C++ 29 и появится (будем верить, что без префикса вроде "co_").

К слову, pattern matching тоже неплохо бы работал с std::expected. Но тут, на мой взгляд, всё очень сильно неопределено (касательно реализации сопоставления с образцом в C++).

? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.

Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.

Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

К слову, pattern matching тоже неплохо бы работал с std::expected.

pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.

Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.

Одна из причин - не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.

Трейт/перегрузку(трейты в расте это такая попытка реализовтаь перегрузку из цпп) это делать позволяют. Т.е. где-то в пользовательском коде можно написать impl чего-то, либо перегрузку.

? - это костыль, который лишь говорит о том, где все сказки "удобно, пм - круто" были фейком. Можно почитать то, что пели последователи result до ?.

Если говорить о реальном коде, особенно о C++(где есть полиморфизм и куда более мощная ситема типов, нежели в раст), то ? становиться бесполезным.

Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

Системы типов я сравнивать не берусь, я в этом далеко не эксперт, однако же синтаксический сахар, который позволяет написать одну строчку вместо 2-3 и сделать код более читабельным, мне бесполезным не кажется.

Касательно типа объекта ошибки, это ожидаемо. Интересно было бы посмотреть, как это выглядит в достаточно больших и долгоживущих проектах, написанных профессиональными разработчикми на Rust (к которым я сам не отношусь). Безусловно, вариант который вы привели, с некоторым базовым типом и выделением объекта на куче выглядит как наиболее очевидное и наивное решение.

Хотя, я тут бегло погуглил, вроде бы даже есть какие-то библиотеки вроде anyhow , которые упрощают жизнь и позволяют подружить типы ошибок из разных библиотек. В общем, думаю, какое-то адеватное решение есть.

pm достаточно слабая концепция, которая во много неполноценна. А уж тем более в C++, если есть полиморфизм и перегрузка.

Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.

Вы имеете ввиду реализацию pm непосредственно в Rust?

Просто в целом, это довольно известная, проверенная временем и широко применяющаяся концепция, например в функциональных языках программирования.

Системы типов я сравнивать не берусь, я в этом далеко не эксперт, однако
же синтаксический сахар, который позволяет написать одну строчку вместо
2-3 и сделать код более читабельным, мне бесполезным не кажется.

Заменять 2-3строчки на одну - это всегда такая себе затея. Она превращает язык в помойку. Когда бездумно добавляется сахар ради сахара.

Если на языке можно реализовать ? - это хорошо. Если же ? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.

Потому добавление сахара - это проблема. И потому, что весь не добавишь. И потому что это идёт в ущерб фичам. Здесь достаточно посмотреть на раст. Где примитивного саха много, а фичей мало.

Касательно типа объекта ошибки, это ожидаемо. Интересно было бы
посмотреть, как это выглядит в достаточно больших и долгоживущих
проектах, написанных профессиональными разработчикми на Rust (к которым я
сам не отношусь). Безусловно, вариант который вы привели, с некоторым
базовым типом и выделением объекта на куче выглядит как наиболее
очевидное и наивное решение.

На уровне пропаганды заявляет о "сохранении типов", в реальности практически любой код на расте использует затирание типов в ошибок.

Есть маргинальные решения где через костыли на макросах пытаются мержить емамы, но это никто не использует в реальности. По крайней мере я такого не видел.

Хотя, я тут бегло погуглил, вроде бы даже есть какие-то библиотеки вроде anyhow
, которые упрощают жизнь и позволяют подружить типы ошибок из разных
библиотек. В общем, думаю, какое-то адеватное решение есть.

Это то самое box dyn err.

Вы имеете ввиду реализацию pm непосредственно в Rust?

Везде, особенно в раст. Да, в более-менее адекватных фп-языках уже давно эмулируют перегрузку через pm. Это куда удобнее, чем искатаь match в лапше. Но там есть всё те же проблемы с тем, что их нельзя расширять из пользовательского кода.

Просто в целом, это довольно известная, проверенная временем и широко применяющаяся концепция, например в функциональных языках программирования.

Проблема только в том, что на функциональных языках программирования ничего не написано. А что пишется - там уже работает естественный отбор.

Допустим, каждый последователь расскажет, что у него там "чистый фп-язык" - все дела. Но в реальности, когда он идёт писать код - всё забывается. И уже язык становиться мультипарадигмальным, а массив всегда был в фп.

Неважно что "ты" считаешь и как думаешь. Есть то, что работает, а что не работает. И когда кто-то начинает что-то делать - реальность всегда вносит коррективы. И вот фп уже не фп. И пм уже не пм.

Если на языке можно реализовать? — это хорошо. Если же? это просто костыль на уровне компилятор, то это плохо. В язык нужно добавлять возможности через которые уже реализуется сахар. А не просто сахар.

Ну так такие возможности в языке есть, и долгое время использовались для этой цели.


А оператор? — это не столько костыль, сколько сокращение для часто используемой операции.

Вот, здесь тоже такое же враньё и прпоагандистская херня.

Ну так такие возможности в языке есть, и долгое время использовались для этой цели.

Здесь пропагандист мусорной скриптухи подменяет тезис. Я говорил именно о ?, а не какой-то макросне. Эта макросня пишется и на сишке. И да, макросня не является языком. И не является языковыми возможностями.

Далее типичная история пропагандиста, который пытается делать вид, что я чего-то не знаю. Я поищу пруфы. https://habr.com/ru/company/yandex/blog/580880/comments/#comment_23564896 - вот пруф.

Я уже об этом выше писал. Это дефолтное пропагандистское дерьмо, сделать вид что я чего-то не понимаю, либо не зная и какой-то клоун мне тут расскажет.

А оператор? — это не столько костыль, сколько сокращение для часто используемой операции.

Нет, это именно костыль. И говорял я именно о нём, а не о чём-то другое. Поэтому данный пропагандист идёт и показывает реализацию ? на скриптухе. Не `if(expr = err) return expr.err` в макросе, а ?

? — это костыль, который лишь говорит о том, где все сказки "удобно, пм — круто" были фейком. Можно почитать то, что пели последователи result до ?.

А что именно они пели? Мне вот необходимость подобного оператора была ясна с самого начала, и я знал что однажды он появится.


Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} — код сломается.

Ну вот у меня в моём коде нечто подобное как раз написано. Первая функция возвращает std::io::Error, вторая — nix::Error. И, представляете, оно работает! Ничего не сломалось!


pm достаточно слабая концепция, которая во много неполноценна [...] Поэтому в том же расте за пределами очевидных учебных примеров pm используется редко. Везде используются трейты.

Вы путаете разные задачи. Иногда требуется фиксированное число вариантов данных с расширяемостью по операциям, иногда — фиксированное число операций с расширяемостью по вариантам данных. Паттерн-матчинг используется в первой задаче, трейты — во второй.


Одна из причин — не расширяемость. pm работает всегда только по закрытому типу, который зачастую объявлен где-то в кишках какой-то библиотеки. Расширить его нельзя. Никак.

Как я уже сказан, паттерн-матчинг расширяем по операциям. Возвращаясь к Result — ну нет никакого смысла "расширять" снаружи это перечисление, в нём всегда Ok и Err, третьего быть не может в принципе. И коды ошибок, возвращаемые библиотекой, тоже незачем расширять снаружи библиотеки. А вот обрабатывать эти коды надо во многих местах, и вынести все операции в интерфейс/трейт/что-то ещё вы не сможете.


трейты в расте это такая попытка реализовтаь перегрузку из цпп

Нет, трейты — это такая попытка реализовать полиморфизм. Успешная попытка, к слову.

НЛО прилетело и опубликовало эту надпись здесь

Кстати, сектанты не палятся. Многие люди не понимают, когда я пишу "да это просто клоуны, обужиенные, которых я не раз глушил - они просто бегают и гадят". Им непонятно как так.

Они обычно шлангуют и несут херню видя "да мы тебя не знаем - мы просто минусуем за что-то". В этот раз они охренели совсем и решили забить на конспирацию.

А, ещё эти клоуны часто рассказывают куллстори про личности, ад-хоминем и прочие куллстори. А теперь они просто признаются "мы будем гадить тебе за то кто ты, а не за то что ты пишешь". Да и гадят они не за то, кто я. А за то, что они множество раз плакались в наших спорах. И это - единственное, что им остаётся делать. Просто нести херню и гадить.

Они считают себя божеством здесь, поэтому им насрать. Всё равно типичный обитатель здешний схавает, потому как он не думает и боится, что пара убогих нагадит ему в карму.

НЛО прилетело и опубликовало эту надпись здесь

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

Ну и рассуждения про "забудлежения" типичная херня. Типичный мейнстримный балабол, который не состоялся qt/си с классами джуном и бегает везде и всюду и пытается через облизывание маргинальной херни набрать очки. Конкурировать с лучшими сложно, поэтому всегда хочется побежать в какой-нибудь хаскель, где обитает всякая студентота и прочие неудачники. Авось там кто заметит. И вот ты уже не на побегушках на какой-то цпп-галере, а имеешь шанс на заметить.

Уровень познаний этого персонажа можно посмотреть в комментах под его клоунадой. Допустим там, где он в очередной раз побежал цпп, потом опозорился, начал мазаться и до сих пор не смог родить атомики.

Подобные персонажи живут за счёт того, что коменты никто не читает. Поэтолму нести можно какую угодно херню.

При этом на хабре часто выпиливается этот позор. Множество моих комментов было выпилено. Всякие позорные темы(типа rust vs swift) авторы выпиливают вместо с собою. А там такое позорище было. Жалко, что вебархив сохранил только начала позора. Но кому интересно может поискать. там и начала достаточно.

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

НЛО прилетело и опубликовало эту надпись здесь

Как же нелепо. Просто съехал с темы. Типичная тактика сектанта - я уже каждого поймал на этом.

В данном случае всё происходит по тому же сценарию. Берётся выдерается кусок моей фразы, а далее начинается балабольство "я не минусовал". При этом как будто бы я утверждал, что данный персонаж что-то минусовал. Да и минусы можно отменить, насколько я знаю.

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

Какой вообще смысл в этой болтовне про минусы? Данный персонаж разве где-то против минусов был? Нет. Он спокойно прибегает, рассказывает "он ничего не понимает" и прочую чушь. Если бы он был против минусов(ах да, не самих минусов, а целенаправленного загаживания).

Ах ну и да. Этот сектант прибежал и начал рассказывать "он ничего не понимает - он лох". Ему это делать можно. Низшие касты сектантов - тут же побежали плюсовать и гадить мне.

Остальное обсуждать бессмысленно, потому что опять везде у вас какие-то сектанты, балаболы и методички.

Вообще какие-то доказательства после этого бесмысленно. Здесь риторика типичного сектанта с синдромом бога, где он - есть мир, а мир есть он и его секта.

Потому как не везде, а конкретно здесь и конкретные сектанты. Но типичная методичка - это отождествлять себя/убогих со всеми.

Типичная клоунада, показываю мат в один ход.

Ну вот у меня в моём коде нечто подобное как раз написано. Первая функция возвращает std::io::Error, вторая — nix::Error. И, представляете, оно работает! Ничего не сломалось!

На кого расчитана эта чушь? На самом деле не на кого - это дымывая завеса для того, чтобы адепты могли гадить. Вон там переписись ниже о много говорит. Практически все тутошние эксперты знают кто я и гадят авансом. Но то такое.

Этот ответ полнейшая чушь, потому как это не работает. На что расчитывает данный пропагандист? Правильно, на то что никто не прочитает. Что он выдернет кусок фразы и будет спорить, но проблема в том, что я нигде не говорил, что оно НЕ РАБОТАЕТ вообще. Я говорил о том, что оно не работает с заявляемыми качествами и не работает без костылей.

Покажу как выглядит этот тезис полностью:

Предположим, что у нас есть две функции. Онда из первой библиотеки, а другая из второй. Как результат нельзя будет напсать {first::f()?; second::f()?;} - код сломается. Там есть страшные костыли на макросне, но в реальном коде просто будет box dyn err. А здесь уже проще написать исключения.

Т.е. я сказал, что там есть и box dyn err костыли, и что есть такие же на макросне. Как же удобно быть пропагандистом этой мусорной скриптухи, когда ты можешь врать, пастить куски фраз. И убогие тебя будут плюсовать, а меня минусовать.

А теперь смотри на то, как данный пропагадист потеряется. Теперь он покажет "работает" без макросни и без dyn err, т.е. любой потери типовой информации.

Ну и да, пусть этот пропагандист объяснит почему же он спастил обрывок фразы и куда потерялось дополнение?

А очень просто оно работает:


#[derive(std::fmt::Debug)]
pub enum MyError {
    IoError(std::io::Error),
    NixError(nix::Error),
}

impl From<nix::Error> for MyError {
    fn from (x: nix::Error) -> Self {
        MyError::NixError(x)
    }
}

impl From<std::io::Error> for MyError {
    fn from (x: std::io::Error) -> Self {
        MyError::IoError(x)
    }
}

// …

fn first() -> std::result::Result<(), nix::Error> { std::unimplemented!() }
fn second() -> std::result::Result<(), std::io::Error> { std::unimplemented!() }

fn example() -> std::result::Result<(), MyError> {
    first()?;
    second()?;
    Ok(())
}

Найдите тут хоть один dyn или макрос или покажите где именно теряется информация.

Один бокс потенциально есть внутри

std::io::Error

Макрос тоже есть в первой строчки вашего снипетта ;) Но писать эти строки с From обычно лень и берут `thiserror` макрос.

Боже, какая нелепая клоунада. Данный пропагандист просто раскрыл мусорный макрос руками.

#[derive(std::fmt::Debug)]
pub enum MyError {
    IoError(std::io::Error),
    NixError(nix::Error),
}

impl From<nix::Error> for MyError {
    fn from (x: nix::Error) -> Self {
        MyError::NixError(x)
    }
}

impl From<std::io::Error> for MyError {
    fn from (x: std::io::Error) -> Self {
        MyError::IoError(x)
    }
}

Эти мусорные костыли то, о чём я говорил и что генерирует макрос. Правда это убожество бездарное в сравнение с макросами, но хоть что-то.

Очевидно, что без этого дерьма оно не работает. Что было мною доказано. Кому интересно - я выше там давал ссылку, где я более подробно разбирал всю эту чушь этих клоунов.

Ладно, мне максимально лень раз в час что-то отвечать в этой помойке.

На самом деле проблема такого подхода возникает когда есть много разных ошибок. Например изначально есть ошибки A, B, C, D. Дальше есть функция x(), которая вызывает функции с потенциальными ошибками A, B и функция y(), которая вызвает ошибки с вариантами A, C, D. Впринципе можно предположить что A это какая-то ошибка более частая - то же io, а B, C, D что то более конкретное доменное. Воощем в итоге получается что у нас `enum X { A, B }` и `enum Y { A, C, D }`. потом появляется функция z() которая вызывает x()? и y()? ... Хорошо делаем дальше `enum Z { X, Y }`... В итоге чтобы найти в этой иерархии наш начальный A приходится ходить внутрь дерева енумов 10ью разными путями. Сделать из дерева плоскую форму ошибок, перегруппировать её, - таких средств нам раст не даёт. Вообщем на третьем-четвёртом уровне вложености всем надоедает, и делают dyn Box (которого вы обещали что не будет)... Люди пишут блоги с какими-то мантрами про то когда на самом деле нужно боксить а когда нет, наплодили десяток либ с макросами, чтобы упростить эту лапшу енумов с From, match и map_err. А в итоге среднестатистческий код на расте не состоит на 90% из обработки ошибок, лишь потому, что используется механизм исключений из С++ спрятанный за макросом panic!.

Работы ведутся только на уровне отдельных тулчейнов/компиляторов. В стандарт пока рано включать - это не самая популярная фича и есть проблемы с диагностикой

А есть ли какие-то продвижки по pattern matching?

В P0627 добавили функцию std::unreachable() для информирования компилятора о недостижимых участках кода (таких, куда программа никогда не заходит во время своего выполнения).

А чем отличия от ifdef или препроцессинг это уже говнокод?

Препроцессором такого не достичь:

int foo(int i) {
    switch (i) {
      case 42: return 64;
      case 142: return 6;
      case 1024: return 0;
    }
    // Без следующей строчки компилятор будет сыпать предупреждениями
    std::unreachable();
}

Вопрос немного не по теме, но все же:

Насколько я понимаю модули из C++20 сейчас на этапе внедрения. В компиляторах они поддержаны: в gcc на ~90% и ~70% в clang.

Но билд системы пока не особенно брались за поддержку: тот же CMake в основной ветке вроде пока никак под модули не адаптировался.

На ваш взгляд, что сейчас является узким местом для того чтобы применять модули для крупных проектов? Есть ли на данный момент удачные примеры их внедрения в яндексе?

Плохая поддержка в компиляторах - основной стоппер. Тот же Boost пока не внедрил модули, в частности потому что у большинства разработчиков на их машинах в компиляторах модули просто не работают.

Понятно, спасибо)

К предложению есть серьёзные возражения https://wg21.link/p1947r0 и много вопросов по поводу расширяемости на пользовательские типы. Пока проблемы не будут решены - предложение не пройдёт... после этого может тоже не пройти. К тому же один из разработчиков executors планировал сделать заход на исключения, может придумает что-то кардинально лучшее.

Это никак не решить. Там слишком сильно. Правда непонятно почему это критика статических исключений. Это критика того мусора, которы пытаются выдать за них. И попытка защититься от всякой скриптуха-пропаганды на тему "исключения говно".


Никаких возражений именно на тему статических исключений там нет. Просто статический исключения - это развитие обычных, их оптимизация. Без ущерба фунrциональности(как любит делать скрипту-пропаганда. Выдавая какой-то дырявый мусор за решение проблемы. Типа result,БЧ и прочий мусор).


А именно что статический исключения на текущем уровне развития C++ невозможно. В массе своей этот набор дырявых костылей поверх си.


Я как раз рассказывал о том, что rtti тормозной мусор именно из-за линковки и прочей сишной атрибутики. Оказывается всё это уже обсуждается, а на меня смотрели с круглыми глазами.


Кому интересно я повторю. Из-за того, что у нас любой T является открытым типом мы никак не можем реализовать нормально rtti, только через строки. Т.е. сами типы в рантайме и их сравнение - это километры строк и их сравнение. В языках с vm мы можем просто заменить всё это на, условно, int. Потому что вм управляет всеми типами существующими в языке.


Аналогично это можно сделать и на C++ сейчас. Если выпилить мусорную линковку, которая итак не работает в С++ сейчас, поэтому все библиотеки являются ho, а всё остальное - си с классами. И сказать компилятору, что другого кода нет(аля -fwhole-program). Тем самым закроются все типы.


Таким образом любой тип - это int, а любое сравнение - сравнение интов. Аналогично можно буду работать что-то типа `any{}.visit([](auto && x) {});`


Особенно с этим не будет никаких проблем в ембедед, где это сделать элементарно(о чём автор и пишет). Но адепты хотят ныть, рассказывать враньё про rtti и исключения, вместо осознания и понимания проблем.



Так же здесь не будут работать всё эти сказки про "а как же большие программы". Такие же истории были про lto, ведь этот костыль(lto) решает ту же проблему. Без проблемы сделали после сделали "параллельное" лто. Тоже самое можно сделать на уровне компилятора. И это не такая уж большая проблема.


По-сути сейчас любая ide решает ту же проблему - как парсить куски исходника отдельно? Обычно это не доходит дальше хедеров, но здесь просто в тему не вкладываются.


В любом случае это нужно сделать и никак далее с линковкой С++ жить не сможет. Либы будут всё сложнее и компиляция будет длится вечно уже на текущем этапе и на хеловоролде.


Даже в рамках микса С++ и си с классами линковка несостоятельна. Потому как результате С++-код разбираться и компилируется десятки, сотни раз. И здесь не могут всякие pch, потому основное время часто занимает инстанцирование и кодогенерация, а не парсинг как таковой.


Поэтому любая раздельная сборка ~95% времени собирает одно и тоже, а не ваш код. Это пытались как-то чинить всякими костылями типа jumbo/unity билдов.


В том же си практически любую программу можно перевести на ho и никаких проблем не будет. Но этим никто не занимается. Люди сами себе создают себе проблемы, своими привычками и невежеством, а потом хаят язык/фиче. Ведь проблему всегда проще найти везде, но не в себе.



lto - это вообще диверсия всякого скама типа раста. Когда ресурсы людские тратятся на "вроде как" универсальные решения. И люди верят этом, но это не так. Это просто рождает всякий скам, который способствует деградации области. lto нужен всяким скриптухам с низким уровнем человеческого капитала. Какая разница что там у убогих? Которые, к тому же, прибегают тебе в комменты и гадят?


Решение это проблемы на уровне языка - открывает множество возможностей, делает ненужным всякие костыли типа lto. И это большая проблема на самом деле. И она везде.



У нас есть, условно, умный и глупый. И вместо того, чтобы поддерживать умного и призывать/способствовать развитию глупого - все всеми силами пытаются глушить умных. Шаблоны? Зачем шаблоны - запретить нахрен. Ведь я их не понимаю, поэтому сжечь - сжечь их, сжечь этих ведьм. Невежество правит миром.


Другие не могут? У других нет возможностей? Мы должны быть такие же. нам ненужно. Не выделяйся. Это то, что нужно понять. Лучше всегда можно свести к худшему, но не наоборот.


Вот адепты си с классами, адепты цпп98 и прочего. Постоянно хейтят возможности крестов, прогресс. Прикрываясь какой-то свободой, какой-то чистотой(расы). Вся их мотивация - это, конечно же, защита своей кормушки. Ладно все привыкли друг другу врать, и делать вид, что какая разница. Но с таким подходом мы никуда не придём.


Люди падают, падают жертвами этой пропаганды. Начинают действительно верить в том, что должен быть выбор, что это как-то спорный вопрос. Но нет. Здесь нет ничего спорного. Здесь нет никакого выбора - вас обманули.



Что теряют адепты си с классами? Ничего. Они ничего не теряют. Им никто не запрещает не использовать все старые возможности. Но при этом другие получают возможности, которые нужны всем.


Поэтому потворство этим персонажам и сами эти персонажи - это враги, это угнетали. Они угнетаю наше желание, желание развиваться. Желание развивать язык. При этом у них никто ничего не забирает. Никто их не обижает.


Но почему же они недовольны? Я уже сказал, но они не скажут. Они недовольны именно тем, что завтра они потеряют работу. Потому что они уже не могут говорить "мы знаем С++", "мы и С++ - это целое", "мы - представляем С++". Тот, кто их нанимает будет видеть, будет видеть код на новом языке. Код лучше, код чище, код проще. Код людей, которые желают развиваться. И эти люди поймут, что их обманывали. Поймут, что нужно выкинуть баласт. Это их страх.


Поэтому они пытаются загнать нас в это болото. Чтобы у нас ничего не было. Чтобы мы барахтались в этом дерьме и бились, бились с ними на фронте этого невежества. Бились по их правилам.



Поэтому лучше всегда сделать вначале мощнее, фичастее, а потом уже ограничивать для определённых групп. Потому как ограничить всегда можно, а расширить нет. Очень хороший пример - это tcp-убожество. Людей действительно защищают этот мусор, который во всём хуже. Вместо того, чтобы на уровне транспорта оставить то, что даёт максимальную свободу. Оставить просто пересылку данных. А уже поверх этого строить то, что нужно.


И доводы там такие же "ой, наше сокет-дерьмо тормозит, потому что наше ядро, api, подходы и прочее - дерьмо". Но это не проблема. Это проблема того, что изначально был выбран мусор в качестве базы, а после все было заточена на него. Поэтому будут боль перехода, но эта боль - это не проблема нового. Этого проблема старого.



Такая же ситуация с теми, кто хочет повесить на остальных своё дерьмо. Допустим, у тебя есть легаси мусор. Ты не хочешь его обновлять? Ты не хочешь в него вкладываться. Какое решение? Сиди на старом компиляторе. Но эти воры хотят украсть у вас, хотят на вас повесить поддержку своего дерьма.


Они постоянно уверяют вас в том, что поддержка нужна. Что нужно тащить всё это в компиляторе и языке. Но на самом деле это просто паразиты и они пользуются слабостью людей. Никаких целей, кроме как украсть у вас - у них нет.


В какой-то степени люди начинают это понимать, но мало. Это тоже самое что выше. Пропаганда и адепты невежества хотят, чтобы вы платили за них. Чтобы вы, способные к большему - копались в дерьме потому, что адепт невежества не может в то, что можете вы. Адепты невежества хотят, чтобы вы платили налог. Чтобы весь новый код, всё что вы пишите - страдало и платило, платило тот самый путём того, что вы не используете новое, лучшее.


Это защищает мусор от конкуренции. Почему они всегда орут "пиши на дерьме", "пиши дерьмо", "пиши как в 98". Потому что они хотят, чтобы вы были в том же болоте, что и они, повторюсь. Чтобы они могли взять ваш код, чтобы за поддержку их мусора для вашего кода заплатили ВЫ, а не ОНИ.



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


Допустим, они пытаются на генериках делать компилтайм и nttp - это невозможно. Но они будут в это верить и будут пытаться. Как раньше они все рассказывали про "инстанцирование - это мусор". И потом через 10 лет они, возможно, дойдут до проблемы.



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


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



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


Я когда-то приводил простой пример. Если мы заменим функции в С++ на нормальный, то эти функции могут, в том числе, эмулировать старое сишное поведение. И пусть там любители нырять в дерьмо в него ныряют, но мы не будем.


Но когда ты это говоришь людям - они начинают "как так, нельзя. Нельзя трогать наши функции". И они настолько жертвы пропаганды, настолько жертвы невежества, что они решительно не понимают, что для них ничего не изменится. Всё будет как раньше. Но нет - нельзя.


Аналогично нельзя альтернативу. Всегда хлебай дерьмо. Альтернативные исключения? Хрен. Альтенативные функции? Хрен. Альтернативное хоть что-то? Хрен. С этим живи. Всегда. Это цпп.



это не комментарий))
это целая статья!!
затравка для holy war

Завезут, но в C++23 не успели.

До тех пор придётся пользоваться заменами, на подобие https://github.com/graphitemaster/incbin

std::expected<int, std::errc> to_int(std::string_view str) {

Подозрительно напоминает

fn to_int(inp: &str) -> Result<i32, err:ErrType> {

Но! Во втором случае есть #[must_use]

А в первом [[nodiscard]].

О, оно тоже есть? Я чувствую, что Rust - это C++ с человеколюбивым синтаксисом. Хотя ownership всё-таки силён...

Насчёт того, насколько синтаксис Rust "человеколюбивый" у меня есть свои соображения :) Хотя, привыкнуть можно и к его особенностям. Я лично нахожу Rust (и его экосистему в целом) во многих аспектах намного более удобным чем "современный C++".

Человеколюбивость Rust'а заключается не в особой прелестности написанного, а в том, что написанное, либо соответствует задуманному, либо вызывает ошибку компиляции. Строг, но человеколюбив. Я вот в треде ниже обнаружил, что string_view по-умолчанию допускает модификацию. Во-первых это не очевидно из сигнатуры функции, во-вторых не вызывает ошибок при компиляции, если я не ожидаю, что функция to_int будет модифицировать мою строку.

что string_view по-умолчанию допускает модификацию

Ещё и крашится на .size() в имеющихся имплементациях, если ему скормили nullptr. Хотя казалось бы, что мешало вернуть 0.

Потому что с чего оно должно возвращать 0, если ноль - это пустая строка?

Вот так ещё больше 😉
auto to_int(std::string_view str) -> std::expected<int, std::errc> {

fn to_int(inp: &str) -> Result<i32, err:ErrType> {

А вот тут начинаются нюансы. У Rust'а ясно написано, что inp - это немодифицируемый slice. А вот в C++ я аж полез читать - и да, string_view - хоть и слайс, но изменяемый. Ой.

std::string_view ни при каких условиях не позволяет изменять строку, на которую ссылается, единственное, что может меняться - указатель на начало и длину при вызове методов вроде remove_prefix. Но и это можно запретить, объявив его как const.

И это логично, ведь неконстантный int или указатель на начало строки тоже могут быть спокойно изменены.

string_view - хоть и слайс, но изменяемый

В каком смысле он изменяемый? В том, что содержимое имеющегося у вас string_view может изменить кто-то снаружи?

Видимо, я плохо прочитал. Но вот ваше замечание мне напомнило, что если мы сделали slice на память и кому-то отдали, то мы всё ещё можем с переменной (для которой slice) творить что попало. Правило исключительного доступа для mut в C++ нету же...

Тут работает обычное правило C++: const view не гарантирует иммутабельности того, на что этот самый const view был получен. std::string_view -- это просто одна из разновидностей того самого const view.

И вот тут-то вот Rust оказывается чуть-чуть более человеколюбивой ситуации, потому что "кто что модифицирует" явно энфорсится компилятором.

Мне не очень нравятся сравнения "а у вас негров линчуют" "а вот в этом языке вот так". Если есть возможность писать на Rust, то не суть важно, как оно в C++. Если же нужно писать на C++, то не суть важно, как оно в Rust.

Ситуации, когда есть возможность выбрать язык для проекта исходя из того, что в одном языке есть одно, а в другом -- другое, встречаются очень редко. Как правило, на выбор языка реализации влияет намного больше факторов, нежели отличия в каких-то фичах/возможностях.

Нет, просто раст куда более ограничен. От этого там существует тысячи костылей, где никакой компилятор ничего не энфорсит, кроме обёрток над ансейф-костылями.

sv - это какая-то часть строки. Этих частей много. С чего вдруг это должно "энфорсить" иммутабельность на исходную строку? Ни с чего.

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

А почему там что-то "энфорсится" - потому что это максимально примитивная реализация. Более примитивного ничего придумать невозможно. И причина этого не в том, что это какое-то "человеколюбие" - как раз таки всё наоборот. Его там нет. На человека там сброшена задча мучится с этими костылями.

Используется подобная максимально примитивная схема потому, что она элементарно реализуется, а возможности реализовать что-то больше не было. Да и нет.

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

И сказки про "лямбда это лямбда" - такие же сказки, потому как вывод типов в лямбде есть потому, что костылём эта лямбда просто воспринимается как кусок кода. Т.е. она не-полиморфна.

Поэтому, даже если принять оправдание "лямбда это лямбда", то почему же лямбда не полноценно? Почему я не могу написать `let id = |x| x; id(10); id(10.);`

Вы немного неправильно понимаете ownership в Rust. Иммутабельность всего в Rust - это дефолт. Вы написали let x: u32 = 4, и x - не мутабельное. Пока вы явно не скажите mut. Поскольку программисты - существа ленивые, они не будут писать mut пока он им не потребуется. Благодаря этому у вас в коде будет минимальное количество mut'ов.

А ещё mut по-умолчанию эксклюзивный. Работать с объектом, который "ёщё где-то меняется" очень сложно, настолько сложно, что редкая птица долетит до середины списка CVE. Если кто-то меняет объект, до момента окончания изменений никто с ним работать не может, и, наоборот, если кто-то объект читает, никто в него писать не может. Это энфорсится бесплатно. Но это дефолт. Если вы такой умный буратина, то вы можете взять Atomic и написать код с шаренным доступом к памяти. loom вам даже может подсунуть херни в рамках выбранной вами модели памяти, и вы сможете оценить разницу между Relaxed и SeqCon.

Насчёт сигнатур. Вы же сами сказали, что в лямбдах прекрасно умеют выводить сигнатуры. А для функций умеют - но не будут, потому что вы правильно написали - сигнатуры, они для человеков, а не для компиляторов (хотя компиляторы в них тоже подглядывают).

Ваш последний пример... Во что он должен скомпилироваться для id(1u8) и для id(1.0f64)? Код-то разный. А полиморфизм должен явно задаваться, потому что если у вас компилятор за вас будет подсовывать полиморфизм там, где вы не ожидаете, то у вас опять получится как Си только с полиморфизмом. "Надо было думать что пишешь".

Вы немного неправильно понимаете ownership в Rust. Иммутабельность всего в Rust - это дефолт. Вы написали let x: u32 = 4, и x - не мутабельное. Пока вы явно не скажите mut. Поскольку программисты - существа ленивые, они не будут писать mut пока он им не потребуется. Благодаря этому у вас в коде будет минимальное количество mut'ов.

К чему эта мантра? Как она связана с тем, что писал я?

А ещё mut по-умолчанию эксклюзивный. Работать с объектом,
который "ёщё где-то меняется" очень сложно, настолько сложно, что редкая
птица долетит до середины списка CVE.

К чему эти мантры? Никакого "не-умолчания нет" и к чему эта клоуна с попыткой делать вид, что я чего-то не понимаю и мне что-то объясняют? Я знаю как это работает.

Если кто-то меняет объект, до
момента окончания изменений никто с ним работать не может, и, наоборот,
если кто-то объект читает, никто в него писать не может.

Зачем, опять же, эта нелепая попытка мне что-то объяснять, когда а) я это знаю, б) я об этом сообщил выше?

Да и никакого "момента изменения" нет. Это всё костыли накостыленные ансейф-хаками и обёрнутые во всякие фокусы. Какое отношение это имеет к делу?

Это энфорсится
бесплатно.

Враньё. Никакого бесплатно нет, есть тысячи костылей с ручной проставкой лафтаймов и тысячей ансейфов даже в примитивной stdlib. Не говоря о том, что лайфатаймы дырявые и будут дырявыми всегда. Пример тот же фейкстатик.

Сейчас мы услышил типичные опрадвания, что дыры не дыры, баги не баги.

Но это дефолт. Если вы такой умный буратина, то вы можете
взять Atomic и написать код с шаренным доступом к памяти. loom вам даже
может подсунуть херни в рамках выбранной вами модели памяти, и вы
сможете оценить разницу между Relaxed и SeqCon.

Атомики на расте не выразимы. Это ансейф-хаки, которые не может работать нормально и не работают. К тому же, зачем мне брать атомики, если мне ненужны атомики?

К тому же какие модели памяти и прочие куллстори, если в расте нет никакой модели памяти - это набор костылей поверех си/ллвм-моделей. Что я там могу узнать?

Вы несколько раз выразили несогласие с unsafe. В чём проблема с unsafe? В целом, в рамках модели rust'а, весь C++ - это один большой unsafe. А в Rust'е сделали так, что его может быть меньше.

unsafe - это не хак, это метод аннотации кода, требующего внимания при review и написании. Вместо того, чтобы требовать повышенного внимания к cpp файлам в целом, можно концентрироваться только на unsafe фрагментах, именно там "умные буратины" показывают как можно делать странное так, чтобы не было больно.

А вы почему-то считаете, что если unsafe, то это духовный провал Rust'а.

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

А ещё не забывайте думать о том, чем зарабатывает человек, которому вы отвечаете. Прям смешно было читать. Воображаемый противник, наделённый всеми чертами, которые вы отрицаете, на которым вы одержали сокрушительную победу.

Насчёт сигнатур. Вы же сами сказали, что в лямбдах прекрасно умеют
выводить сигнатуры. А для функций умеют - но не будут, потому что вы
правильно написали - сигнатуры, они для человеков, а не для компиляторов
(хотя компиляторы в них тоже подглядывают).

Меня так удивляют пропагандисты, которые начинают с трансляции дефолтной методички, которуя в своём комменте разобрал.

Никакого вывода типа возврата в лямбдах нет, потому как лямбда не полиморфна. Тип там выводится костылём, код лямбды просто посдтавляется в контекст использования.

Бредни про "для человеком" мне даже комментировать лень. Потому что сигнатуры в расте сделаны именно что для компилятора, потому что вывода типов нет, полиморфиная модель убогая и прочее. Поэтому все эти костыли пишутся руками и уж никаким образом не для человека.

И, опять же, в данном случае пропаганда нам не сообщет о том - почему вдруг в лямбде сигнатура ненужна, а в функции нужна.

Ваш последний пример... Во что он должен скомпилироваться для id(1u8) и для id(1.0f64)?
Код-то разный. А полиморфизм должен явно задаваться, потому что если у
вас компилятор за вас будет подсовывать полиморфизм там, где вы не
ожидаете, то у вас опять получится как Си только с полиморфизмом. "Надо
было думать что пишешь".

Чего? Какие-то совсем жидкие оправдания. Лямбда так же может быть полиморфна, если она находится в другом контексте. И никаким образом явно это не задаётся.

Да и я могу просто передать в лямбду &dyn trash и всё там будет вызываться.

Поэтому все эти разговоры - оправдания, поэтому они такие дырявые. Если нужно явно, то почему void проставляется неявно? Либо лайфтаймы? А почему async-костыли на 99% состоят из неявно и там в сигнатурах совершенно не то, что в реальности? Почему into и прочее - это уже не плохо и не "неявно"?

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

Уже группая поддержки подключилась и гадят. Прибежал проповедовать. Все ответы - пустые лозунги и игнорирование доводов оппонента. Ещё у них там на всех разум коллективный, поэтому любое "фи" в адрес пропагандиста, либо обожаемой им скриптухи - сразу набегают и гадят.

Ах да, забыл. Каждый пропагандист работает по одной и той же методичке. Вы можете посмотреть это выше, либо где-либо ещё. Они всегда делают вид, что оппонент чего-то не понимает и этот гений пришёл и объяснил мне про ссылки, про владения и про раст.

Обычно они настолько приисполняются, что начинают тупо повторять то, что уже сказано оппонентов. Пишешь "ссылка одна" и тебе начинается "а вот в расте ссылка то одна, а ты не знал". Во-первых я знал, потому что это очевидная херня. Во-вторых я это же написал выше.

Так, уже группая поддержки, которую пропагандисты собирают по всяким чатам, начинает гадить в карму. Фиксирую. На начала моих ответов было -3/4.

Сейчас начнутся сказки, что они минусуют меня за то, что называю их пропагандистами. Придут всякие "я случайно проходит"-персонажи.

Фиксирую сразу. Гадить начали с первого же поста, в том числе в карму. Пропагандисты были уже после.

Фиксирую набег какого-то бота. Нагадил в карму и минуснул все комменты, которые были на тот момент написаны. В том числе и коммент:

Это обёртка над тем, что уже тысячи лет в нормальных компиляторах, а именно __builtin_unreachable

Этот, т.е. здесь попросту нет ничего за что минусовать. Но боту плохую подготовку получил и ещё не научился минусовать без такого явного палева.

The class template basic_string_view describes an object that can refer to a constant contiguous sequence of char-like objects with the first element of the sequence at position zero.
Note: iterator and const_iterator are the same type because string views are views into constant character sequences.

Спасибо, я плохо прочитал. Но выше указали на ещё более интересный вопрос. Если я поверх строки сделал string_view, я могу эту строку продолжать менять?

Не больше. fn в отличии от auto в цпп - это костыль, который обусловлен слабостью "парсера". -> в цпп имеет смысла, когда как в расте - это просто костыль, потоу как лево всегда занято костылём ввиде fn/let и прочего.

Право используется потому, потому как это даёт возможность использовать парметры как часть типа. Допустим `(auto x) -> decltype(x.err)`

Поэтому, допустим, сущуествует template<>. Оно нужно для того, чтобы можно было определить теплейт-параметр до типа возврата. `T <T>f` - такое написать нельзя. Более-менее смышлёные последователи права ссылаются на то, что право у них по этой причине. Нет. Право там именно потому, что fn.

Про fn - это пошло ещё с паскаля, как пример максимально примитивного парсинга. Суть там простая. У нас есть описание неких грамматических правил и нам нужно узнать то, какому правилу соответствует набор токенов, в простом случае.

Вот самый просто способ - это максимально сильно упрощать грамматику, уменьшая коллизии в правилах. А когда от них уйти нельзя - просто тупо писать идентификатор правила слева.

Т.е. все эти fn/let и прочее - это синтаксический мусор, который не имеет никакого смысла, кроме как для упрощения разбора. Упрощение разбора никогда актуальным не являлось. Поэтому все сказки "это для оптимизации" - являются чушью. Достаточно посмотреть на время компиляции раста. Это экономия на спичках, которая крайне сомнительна.

Подобный подход - удел студентов, которые только начинают писать языки.

Сейчас очень часто можно видеть использование auto -> в цпп. Это просто пропагандисткий причём призваный сместить внимание с отстутствия вывода типа возврата в расте. Потому как писать подобным образом смысла не имеет, а когда имеет - аналога в расте существовать не может в силу его скудных возможностей.

Они базируются на рефлексии, а рефлексия окажется в лучшем случае в C++26. Так что пока ожидаем

v | std::views::chunk(2); // {['n', 'o'], ['p', 'p']}
v | std::views::slide(2); // {['n', 'o'], ['o', 'p'], ['p', 'p']}

А оно в таком виде будет модифицировать входные контейнеры разве? Я думал range-алгоритмы ленивые.

Да, ranges ленивые и я походу тоже: в коменте справа я написал, что мы получим если пройдёмся по всем элементам диапазона и сохраним их куда-нибудь.

Constexpr math - спасибо что в этом столетии! Главное, чтоб из-за обратной совместимости нам не замутили std::math::cos в дополнение к существующему std::cos, например...

Не, вроде такое не планируется :)

Теперь можно получится продвинуть бумагу на constexpr для <cstring>. А то как-то неправильно писать std::string_view{s}.size() вместо std::strlen(s)

Напишу просто предложение, которое поможет многим людям. Да и реализуется оно достаточно просто. Сейчам мы можем передавать в asm только литералы строковые. Передать же туда constexpr-строку мы не можем. Нужно расширить asm, чтобы он мог принимать constexpr-строки.

Тогда можно будет писать кодогенерацию в комплейтайме напрямую.

Боюсь что придётся вначале стандартизировать asm: http://eel.is/c++draft/dcl.asm

Не планируется что-нибудь для управления ограничениями на нововведения и вообще на фичи, коих всё больше и больше.
#pragma require список требований к компилятору
Наример
#pragma requie c++20
#pragma forbid raw_pointer
#pragma forbid fpu

Что бы если фича не запрошена или явно запрещена, что бы она останавливала компиляцию, даже если она поддерживается.
ограничениями на нововведения

ну оно есть, компилируйте себе спокойно код с -std=c++98, никакая новая фича не проскочит.
А если вы хотите фишечки по одной отключать в одной TU, сойдут с ума все — и разработчики компилятора, и разработчики библиотек, это поддерживать нереально, там не просто комбинаторный взрыв а атомная бомба получится.
С хедерами это крайне сложно сделать. С модулями уже попроще, есть даже предложение насчет «эпох». www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1881r0.html

Было бы круто. Но, если честно, слабо верится, что люди смогут договорится что в конкретную эпоху должно входить.
Было бы круто если бы описание эпох было организовано в виде скрипта
НЛО прилетело и опубликовало эту надпись здесь
Мне бы больше понравился такой вариант:
int err=0;
if invariant(err==0) {
  err=fn1();
  err=fn2();
  ..
} else {
  show(err);
}

чтобы инвариант проверялся сам при каждом обновлении и в случае его нарушения переходило в ветку else. Пока такое можно только на исключения сделать.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий