Не понятно написал, попробую раскрыть мысль в этом комментарии. Я "подсадил" друзей и родственников на эти программы. Они, как раз, более чем обычные пользователи и GUI могут пользоваться yt-dlp без проблем. Но часто ютуб ломает своё все, из-за чего ломается yt-dlp и мне приходится этим людям объяснять:
как и что нужно скачать с гитхаба;
как найти расположение файла по ярлыку;
куда же этот новый yt-dlp нужно положить
и т.д.
То есть люди как раз самые что ни на есть обычные и кроме этого у них особых проблем после начальной настройки нет.
Для yt-dlp можно без проблем найти отдельные GUI, вроде Open Video Downloader или Seal. Объяснять, как обновить yt-dlp после очередного обновления ютуба сложно, но вполне возможно.
Оракл в свое время начал выпуск своей СУБД с версии 2, мотивируя тем, что никто не хочет пользоваться первой версией
Так в этом и проблема. Сам по себе номер версии вообще ничего не значит. Изменение минорной версии не гарантирует, что у кода не изменилось API (хотя для этого есть помощники). Можно тогда просто на версии с датами перейти (вроде 2024.04.1), код надежнее это не сделает, зато выглядит солидно.
С 0.X.Y версиями ситуация получается странная - даже если библиотека уже готова для использования в продакшен среде, то переход на 1.0.0 создаст много проблем с не очевидными выгодами. Менять мажорную версию без нарушений обратной совместимости странно, т.к. cargo автоматически не обновит версию с 0.X.Y до 1.0.0, что заставляет всех пользователей библиотеки делать это вручную. А из плюсов только то, что версия 1.0.0+ выглядит солиднее.
Так и написали бы об этом. Все, что в вашем примере кода говорит о том, что там уже есть многопоточность - это три буквы par. А, как в статье и написано, у меня 0 опыта в C++, я понятия не имею, что эта штука сделает. Вместо обвинений в токсичности лучше бы написали такой комментарий, он был бы гораздо полезнее для всех.
То есть, вы считаете, что эта статья о сравнение Rust и C (даже проигнорируем тот факт, что я так не считаю, просто часто это то, как люди воспринимают Rust. С Python и Golang сравнений больше), подменяете его своим аргументом "в контексте сравнения с C++, потому что считаю сравнение Rust и Си бессмысленным и просто неправильным" и пытаетесь разбить уже свой собственный аргумент? Да это же соломенное чучело.
Да по вашим комментариям можно целый курс по черри-пикингу сделать. Я даже название придумал - "Краткий курс черри-пикинга или как проигнорировать контекст дискуссии так, чтобы выставить своего оппонента максимальным идиотом".
Если вы забыли (или не знали) контекста и этой дискуссии, то давайте я вам (и всем, кто будет читать это после) расскажу:
у меня в статье есть пример кода, который использует потоки:
Заголовок спойлера
let rows = img.rows_mut().collect::<Vec<_>>();
std::thread::scope(|scope| {
...
for (y, chunk) in rows.into_iter().enumerate() {
scope.spawn(move || {
...
for (x, pixel) in chunk.enumerate() {
let mut color = Color::default();
for _ in 0..samples_per_pixel {
...
}
*pixel = color.as_rgb(samples_per_pixel);
}
...
});
}
});
img.save("image.png").unwrap();
Там же указаны гарантии языка для этого кода:
Заголовок спойлера
в этом коде нет гонок данных;
невозможно написать эту программу так, чтобы получить пересекающиеся задачи;
невозможно написать эту программу так, чтобы в момент img.save хоть один из потоков был бы еще жив.
std::ranges::for_each(std::execution::par,
rows | std::views::enumerate,
[](auto const i, auto const& el){
// logic
});
На это я отвечаю " А что будет, если не "сделать { }"? И что будет, если не "в конце jthread сделает join()"? Потому, что в Rust это нельзя не сделать, код не скомпилируется". Потому, что я точно знаю, что если не сделать join() для обычного потока, то это чтение и запись без синхронизации, т.е. это сразу UB и сделать join() автоматически при выходе из скоупа это, насколько я знаю, плохая идея.
В контексте все немного по-другому выглядит, не находите? Хотя кого я обманываю, даже в этой статье вы не раз, не два, не три, не четыре, не пять, не шесть, а семь раз пишете либо фактически неверные утверждения, либо манипулируете не знающим контекста читателем.
Но почему то в одном надо рассматривать ситуацию, когда какой-то недотепа допускает глупую ошибку, но в другом можно на это не обращать внимание, ведь там есть слово, которое его ТОЧНО остановит
А вы попробуйте привести пример, когда человек случайно не просто unsafe блок напишет, но еще и случайно напишет такой код, который UB вызовет (спойлер: unsafe блок не выключает никакие проверки, даже если его случайно написать, то ничего не изменится).
тогда докажи, что добавленные строки это НЕ сортировка и проверка уникальности элементов с выдачей ошибки, если они ен уникальные
Может мне еще заодно доказать, что он ракеты на Марс не запускает?
За минуту можно найти, что "это НЕ сортировка и проверка уникальности элементов с выдачей ошибки, если они ен уникальные":
/// This checks every index against each other, and against `len`.
///
/// This will do `binomial(N + 1, 2) = N * (N + 1) / 2 = 0, 1, 3, 6, 10, ..`
/// comparison operations.
fn get_many_check_valid<const N: usize>(indices: &[usize; N], len: usize) -> bool {
// NB: The optimizer should inline the loops into a sequence
// of instructions without additional branching.
let mut valid = true;
for (i, &idx) in indices.iter().enumerate() {
valid &= idx < len;
for &idx2 in &indices[..i] {
valid &= idx != idx2;
}
}
valid
}
Это шутка такая? Может быть все же надо смотреть на то, какие операции происходят? А то 1 стока блокирующего сискола, оказывается, выполняется столько же, сколько и мув из регистра в регистр. Вот чудеса!
я показывааю что оно тут есть
Так покажите, где в релиз версии get_many_check_valid "создание массив, сортировка и проверка на наличие повторений". Вот конкретные строки. И при этом я пытаюсь "с темы съехать"?
Тогда получается 146 строк асм против 97 когда неизвестный индекс.
"создание массив, сортировка и проверка на наличие повторений", видимо, в количестве строк асма выражается, ясно, понятно. Не помните уже, с чего разговор то начался? Могу напомнить, вы в одном комментарии умудрились сделать 4 утверждения, все из который ложны (включая "создание массив, сортировка и проверка на наличие повторений" для не дебаг версии).
И без тыканий, пожалуйста, мы с вами брудершафт не пили.
Параллельный код. Это (без иронии) замечательно, что в C++ можно написать так же удобно.
А вот про безопасность давайте поговорим отдельно. "В плюсах сделаете { } просто и в конце jthread сделает join()". А что будет, если не "сделать { }"? И что будет, если не "конце jthread сделает join()"? Потому, что в Rust это нельзя не сделать, код не скомпилируется. В обычные потоки (не scoped) нельзя передать не 'static объект (объект, который живет всю жизнь программы). И не в смысле пока жив main, но и после этого;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Обработка ошибок через монады
"Обработка ошибок через монады есть и в плюсах" И надо поддерживать как обработку ошибок монадами, так и исключениями одновременно;
"Какие проблемы у монад я написал в первом комментарии" Да не то, чтобы написали, кроме "Это ужасный код ... все равно смотрится как каша". Дело ваше, чувство прекрасного у всех свое. Меня же больше интересует практическая сторона вопроса, чем эстетическая;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Рефакторинг
"система типов в плюсах не слабее, чем в расте. Думаю с этим спорить бессмысленно". Не готов спорить, у меня нет достаточных компетенций в C++;
"Перечисления в плюсах это std::variant, паттерн матчинг это std::visit". То же самое, не готов спорить, но первый комментарий из первой ссылки из гугла, которую я открыл, с этим не согласен;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Факты
"Слишком мало контекста". Ответы на все эти вопросы вы могли бы получить просто посмотрев выступление, из которого эти тезисы;
"Rust навязывает и заставляет писать правильный код, в отличии от большинства других языков". Ужас то какой, заставляет писать правильный код. Как жить то после такого;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"? Где хотя бы противоречие или несогласие, раз уж вы решили написать почти полторы тысячи символов по этому поводу?
Время компиляции
Видимо хоть в чем-то мы согласны, это уже неплохо;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Сложность
"Rust сложным, насколько я понял по множеству статей, кажется людям, которые переходят с языков вроде python. И причины тут очевидны" Причины настолько очевидны, что их и указывать не надо? И, кстати, будем знакомы, я как раз начал изучать Rust после Python. И я считаю, что Rust - простой;
"Насчет Си - наверно под "маленький" имеются ввиду концепции в языке". Это ему не помогает, в C приходится думать о слишком большом количестве вещей и из-за этого никто не способен писать безопасный код на C и/или C++;
"Option<NotNull<Node<T>>>". Насколько я знаю, в стандартной билбиотеке плюсов код гораздо более нечитаем, тут же просто по переводу можно довольно точно понять, что происходит;
"если там всегда есть объект". Потому, что не всегда там есть объект;
"А если он есть не всегда, тогда зачем NotNull?". Чтобы нельзя было разыменовать нулевой указатель;
"А что вообще значит ситуация, когда Option == None". Что объекта там нет;
"Я под обработкой ошибок понимаю считай весь код, который есть в вашей версии, но нет в моей". Допустим, мне вообще не кажется это важным;
"Поэтому я и сказал, что мне не нравятся исключения в C++". Тогда я не понимаю примера в вашем первом комментарии. Вы не хотите писать "ужасный код" для обработки ошибок как значений и вам не нравятся исключения. Вы хотите жить в мире, где ошибок просто не существует? Я тоже был бы не против, только пока такого не предвидится;
"Наверняка и ваш код на Rust можно сделать более красивым". В данном случае можно т.к. filter_map_ok принимает замыкание, которое возвращает Option. Получилось вот так:
Мне по большому счету все равно. Код с and_then лучше тем, что ему не надо быть в функции, которая возвращает Option. Может быть когда стабилизируют try_blocks так будет удобнее во всех случаях. Для меня большой разницы нет, Option все равно придется как-то проверить и никакая магия не поможет избавиться от последнего map.
В итоге, вы написали очень много слов про C++. У меня в статье C++ упоминается 7 раз. 5 из них это цитаты (или перефразирование цитат) и еще 2 во вступлении. Так что я не очень понимаю, к чему эта гора текста про C++, про который я в статье не говорю? Кто ж виноват в том, что в статьях, из которых я брал тезисы, очень много сравнений с C++.
Я отвечал на пункты по мере прочтения и только в конце понял, что вы мне не противоречите нигде, кроме эстетической составляющей кода. На эту тему дискутировать я не хочу, мне в большой степени все равно, как оно выглядит. Пусть каждому нравится свой стиль кода, я не против.
Не понятно написал, попробую раскрыть мысль в этом комментарии. Я "подсадил" друзей и родственников на эти программы. Они, как раз, более чем обычные пользователи и GUI могут пользоваться yt-dlp без проблем. Но часто ютуб ломает своё все, из-за чего ломается yt-dlp и мне приходится этим людям объяснять:
как и что нужно скачать с гитхаба;
как найти расположение файла по ярлыку;
куда же этот новый yt-dlp нужно положить
и т.д.
То есть люди как раз самые что ни на есть обычные и кроме этого у них особых проблем после начальной настройки нет.
Для yt-dlp можно без проблем найти отдельные GUI, вроде Open Video Downloader или Seal. Объяснять, как обновить yt-dlp после очередного обновления ютуба сложно, но вполне возможно.
Это не автор считает, это стандарт так считает.
Так в этом и проблема. Сам по себе номер версии вообще ничего не значит. Изменение минорной версии не гарантирует, что у кода не изменилось API (хотя для этого есть помощники). Можно тогда просто на версии с датами перейти (вроде 2024.04.1), код надежнее это не сделает, зато выглядит солидно.
С
0.X.Yверсиями ситуация получается странная - даже если библиотека уже готова для использования в продакшен среде, то переход на1.0.0создаст много проблем с не очевидными выгодами. Менять мажорную версию без нарушений обратной совместимости странно, т.к. cargo автоматически не обновит версию с0.X.Yдо1.0.0, что заставляет всех пользователей библиотеки делать это вручную. А из плюсов только то, что версия1.0.0+выглядит солиднее.Так и написали бы об этом. Все, что в вашем примере кода говорит о том, что там уже есть многопоточность - это три буквы
par. А, как в статье и написано, у меня 0 опыта в C++, я понятия не имею, что эта штука сделает. Вместо обвинений в токсичности лучше бы написали такой комментарий, он был бы гораздо полезнее для всех.То есть, вы считаете, что эта статья о сравнение Rust и C (даже проигнорируем тот факт, что я так не считаю, просто часто это то, как люди воспринимают Rust. С Python и Golang сравнений больше), подменяете его своим аргументом "в контексте сравнения с C++, потому что считаю сравнение Rust и Си бессмысленным и просто неправильным" и пытаетесь разбить уже свой собственный аргумент? Да это же соломенное чучело.
Да по вашим комментариям можно целый курс по черри-пикингу сделать. Я даже название придумал - "Краткий курс черри-пикинга или как проигнорировать контекст дискуссии так, чтобы выставить своего оппонента максимальным идиотом".
Если вы забыли (или не знали) контекста и этой дискуссии, то давайте я вам (и всем, кто будет читать это после) расскажу:
у меня в статье есть пример кода, который использует потоки:
Заголовок спойлера
Там же указаны гарантии языка для этого кода:
Заголовок спойлера
в этом коде нет гонок данных;
невозможно написать эту программу так, чтобы получить пересекающиеся задачи;
невозможно написать эту программу так, чтобы в момент
img.saveхоть один из потоков был бы еще жив.feelamee на это пишет, что "На плюсах это пишется не сложнее" и "Думаю тут не осталось сомнений, что в таком простом варианте, у плюсов и раста примерно одинаковые удобства и безопасность". Если "В плюсах сделаете { } просто и в конце jthread сделает join()." с таким кодом:
Заголовок спойлера
На это я отвечаю " А что будет, если не "сделать { }"? И что будет, если не "в конце jthread сделает join()"? Потому, что в Rust это нельзя не сделать, код не скомпилируется". Потому, что я точно знаю, что если не сделать
join()для обычного потока, то это чтение и запись без синхронизации, т.е. это сразу UB и сделатьjoin()автоматически при выходе из скоупа это, насколько я знаю, плохая идея.В контексте все немного по-другому выглядит, не находите? Хотя кого я обманываю, даже в этой статье вы не раз, не два, не три, не четыре, не пять, не шесть, а семь раз пишете либо фактически неверные утверждения, либо манипулируете не знающим контекста читателем.
Вы бы определились уже со своей позицией, а то я только в комментариях к этой статье видел:
Да не нужна никому эта ваша безопасность;
Есть два языка, оба языка позволяют писать и безопасный и небезопасный код и неявное продолжение, что ну раз можно, то и разницы нет;
что в таком простом варианте, у плюсов и раста примерно одинаковые удобства и безопасность к слову о "Я тут даже не пытался никому доказать, что безопасность плюсов >= безопасность раста" и несмотря на "В плюсах сделаете { } просто и в конце jthread сделает join()" вместе с отсутствием ответа на вопрос "что будет, если ... забыть 'сделать { }'?";
Я тоже вхожу в эти 85% . Тут все просто - Rust навязывает и заставляет писать правильный код, в отличии от большинства других языков. Те же C++ дают вам полную свободу 85% это про "85% опрошенных разработчиков сообщили, что у них выросла уверенность в корректности кода по сравнению с другими языками программирования", т.е. вы сами считаете, что Rust безопаснее.
Это Rust сообщество токсичное и фанатичное, конечно.
Особенно это смешно, если проследить за последовательностью событий:
что в таком простом варианте, у плюсов и раста примерно одинаковые удобства и безопасность вместе с "В плюсах сделаете { } просто и в конце jthread сделает join()".
увиливание от ответа на вопрос "что будет, если ... забыть 'сделать { }'?";
сравнение возможности "забыть { }" с unsafe Rust;
Я правильно понимаю, что этот код настолько же безопасен, как "безопасен" и unsafe Rust?
А вы попробуйте привести пример, когда человек случайно не просто unsafe блок напишет, но еще и случайно напишет такой код, который UB вызовет (спойлер: unsafe блок не выключает никакие проверки, даже если его случайно написать, то ничего не изменится).
Вам бревно в глазу не мешает?
Только что проверил,
golangci-lint runигнорирует такой код (golangci-lint has version 1.55.2):Видимо потому, что
true- слишком незначительная часть языка для того, чтобы true было ключевым словом.Это замечательно, только вот как мне это поможет избежать (это хотя бы можно
s[:3:3]починить):https://go.dev/play/p/7dkrDMD4v9D
Или такой гайзенбаг, когда то, упадет код или тихо будет работать неправильно зависит от того, был ли слайс переалоцирован или нет:
https://go.dev/play/p/Fud-Dmdgq1u
А можно и не рассмотреть. Unsafe не появится если забыть что-то сделать.
Не знаю, как у вас получилось, но вы проигнорировали самое важное предложение в середине комментария:
Действительно, "что раст что плюсы имеют недостатки и преимущества в этом", вообще никакой разницы.
Просто замечательно. Я даже не знаю, как это прокомментировать.
Ответ находится во втором абзаце моей статьи.
Примеры "половины фактов, которые не имеет смысла, а остальная половина спорна", а не сравнения Rust с C++.
Меня вы в этом не убедили.
Может мне еще заодно доказать, что он ракеты на Марс не запускает?
За минуту можно найти, что "это НЕ сортировка и проверка уникальности элементов с выдачей ошибки, если они ен уникальные":
Это шутка такая? Может быть все же надо смотреть на то, какие операции происходят? А то 1 стока блокирующего сискола, оказывается, выполняется столько же, сколько и мув из регистра в регистр. Вот чудеса!
Так покажите, где в релиз версии
get_many_check_valid"создание массив, сортировка и проверка на наличие повторений". Вот конкретные строки. И при этом я пытаюсь "с темы съехать"?"создание массив, сортировка и проверка на наличие повторений", видимо, в количестве строк асма выражается, ясно, понятно. Не помните уже, с чего разговор то начался? Могу напомнить, вы в одном комментарии умудрились сделать 4 утверждения, все из который ложны (включая "создание массив, сортировка и проверка на наличие повторений" для не дебаг версии).
И без тыканий, пожалуйста, мы с вами брудершафт не пили.
То ничего не изменится:
Заголовок спойлера
Такой код не скомпилируется.
to_stringвозвращает строку, а замыкание вfilter_map_okдолжно возвращатьOption. Но можно сделать еще лучше:Заголовок спойлера
Параллельный код. Это (без иронии) замечательно, что в C++ можно написать так же удобно.
А вот про безопасность давайте поговорим отдельно. "В плюсах сделаете { } просто и в конце jthread сделает join()". А что будет, если не "сделать { }"? И что будет, если не "конце jthread сделает join()"? Потому, что в Rust это нельзя не сделать, код не скомпилируется. В обычные потоки (не scoped) нельзя передать не 'static объект (объект, который живет всю жизнь программы). И не в смысле пока жив main, но и после этого;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Обработка ошибок через монады
"Обработка ошибок через монады есть и в плюсах" И надо поддерживать как обработку ошибок монадами, так и исключениями одновременно;
"Какие проблемы у монад я написал в первом комментарии" Да не то, чтобы написали, кроме "Это ужасный код ... все равно смотрится как каша". Дело ваше, чувство прекрасного у всех свое. Меня же больше интересует практическая сторона вопроса, чем эстетическая;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Рефакторинг
"система типов в плюсах не слабее, чем в расте. Думаю с этим спорить бессмысленно". Не готов спорить, у меня нет достаточных компетенций в C++;
"Перечисления в плюсах это std::variant, паттерн матчинг это std::visit". То же самое, не готов спорить, но первый комментарий из первой ссылки из гугла, которую я открыл, с этим не согласен;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Факты
"Слишком мало контекста". Ответы на все эти вопросы вы могли бы получить просто посмотрев выступление, из которого эти тезисы;
"Rust навязывает и заставляет писать правильный код, в отличии от большинства других языков". Ужас то какой, заставляет писать правильный код. Как жить то после такого;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"? Где хотя бы противоречие или несогласие, раз уж вы решили написать почти полторы тысячи символов по этому поводу?
Время компиляции
Видимо хоть в чем-то мы согласны, это уже неплохо;
Что же из этой части в моей статье "не имеет смысла", а что "спорно"?
Сложность
"Rust сложным, насколько я понял по множеству статей, кажется людям, которые переходят с языков вроде python. И причины тут очевидны" Причины настолько очевидны, что их и указывать не надо? И, кстати, будем знакомы, я как раз начал изучать Rust после Python. И я считаю, что Rust - простой;
"Насчет Си - наверно под "маленький" имеются ввиду концепции в языке". Это ему не помогает, в C приходится думать о слишком большом количестве вещей и из-за этого никто не способен писать безопасный код на C и/или C++;
"
Option<NotNull<Node<T>>>". Насколько я знаю, в стандартной билбиотеке плюсов код гораздо более нечитаем, тут же просто по переводу можно довольно точно понять, что происходит;"если там всегда есть объект". Потому, что не всегда там есть объект;
"А если он есть не всегда, тогда зачем NotNull?". Чтобы нельзя было разыменовать нулевой указатель;
"А что вообще значит ситуация, когда Option == None". Что объекта там нет;
"Я под обработкой ошибок понимаю считай весь код, который есть в вашей версии, но нет в моей". Допустим, мне вообще не кажется это важным;
"Поэтому я и сказал, что мне не нравятся исключения в C++". Тогда я не понимаю примера в вашем первом комментарии. Вы не хотите писать "ужасный код" для обработки ошибок как значений и вам не нравятся исключения. Вы хотите жить в мире, где ошибок просто не существует? Я тоже был бы не против, только пока такого не предвидится;
"Наверняка и ваш код на Rust можно сделать более красивым". В данном случае можно т.к.
filter_map_okпринимает замыкание, которое возвращаетOption. Получилось вот так:Заголовок спойлера
Мне по большому счету все равно. Код с
and_thenлучше тем, что ему не надо быть в функции, которая возвращаетOption. Может быть когда стабилизируют try_blocks так будет удобнее во всех случаях. Для меня большой разницы нет,Optionвсе равно придется как-то проверить и никакая магия не поможет избавиться от последнегоmap.В итоге, вы написали очень много слов про C++. У меня в статье C++ упоминается 7 раз. 5 из них это цитаты (или перефразирование цитат) и еще 2 во вступлении. Так что я не очень понимаю, к чему эта гора текста про C++, про который я в статье не говорю? Кто ж виноват в том, что в статьях, из которых я брал тезисы, очень много сравнений с C++.
Я отвечал на пункты по мере прочтения и только в конце понял, что вы мне не противоречите нигде, кроме эстетической составляющей кода. На эту тему дискутировать я не хочу, мне в большой степени все равно, как оно выглядит. Пусть каждому нравится свой стиль кода, я не против.
Простите, но я не понял, что вы хотели показать в примере с вектором, там же написано следующее:
push_back, emplace_back - If the vector changed capacity, all of them;
insert, emplace - If the vector changed capacity, all of them;
resize - If the vector changed capacity, all of them.
Полагаться на то, что у ветора при добавлении не изменится
capacity- это дело рискованное.В связном списке Rust точно так же не инвалидирует итератор.