Наследование и дженерики понятия не связанные, они друг с другом не связаны и друг на друга не влияют.
Для дженериков есть трейты, они очень хорошо эту задачу выполняют.
Вместо наследования можно использовать композицию (добавлять "наследуемый" тип в качестве внутреннего поля). Чтобы не было так больно копипастить не изменившиеся методы есть, например, delegate.
Первый тип не сложный, легко пишется, и неплохо помогает, но все же не настолько могущественны как второй тип.
Чтобы макросы второго типа (я просто не уверен, как нормально это "Macro By Example" перевести, чтобы было понятно что это) писать было проще и веселее можно использовать другие макросы, например quote. Вот мой личный пример его использования.
Не надо оператор is использовать для сравнения чисел, это не проверка на равенство, а проверка идентичности (т.е. что объект один и тот же) ((0.1+0.2) == 0.3 тоже выведет False).
Вот пример, почему такое его использование приведет к проблемам:
Заголовок спойлера
x = 100
y = 100
print(x is y) # Output: True
print(id(x))
print(id(y))
x += 100
y += 100
print(x is y) # Output: True
print(id(x))
print(id(y))
x += 100
y += 100
print(x is y) # Output: False
print(id(x))
print(id(y))
Не понятно написал, попробую раскрыть мысль в этом комментарии. Я "подсадил" друзей и родственников на эти программы. Они, как раз, более чем обычные пользователи и 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 утверждения, все из который ложны (включая "создание массив, сортировка и проверка на наличие повторений" для не дебаг версии).
И без тыканий, пожалуйста, мы с вами брудершафт не пили.
Наследование и дженерики понятия не связанные, они друг с другом не связаны и друг на друга не влияют.
Для дженериков есть трейты, они очень хорошо эту задачу выполняют.
Вместо наследования можно использовать композицию (добавлять "наследуемый" тип в качестве внутреннего поля). Чтобы не было так больно копипастить не изменившиеся методы есть, например, delegate.
Еще для снижения количества копипасты есть макросы, даже 2 вида: Macros By Example и процедурные макросы.
Первый тип не сложный, легко пишется, и неплохо помогает, но все же не настолько могущественны как второй тип.
Чтобы макросы второго типа (я просто не уверен, как нормально это "Macro By Example" перевести, чтобы было понятно что это) писать было проще и веселее можно использовать другие макросы, например quote. Вот мой личный пример его использования.
Не надо оператор
isиспользовать для сравнения чисел, это не проверка на равенство, а проверка идентичности (т.е. что объект один и тот же) ((0.1+0.2) == 0.3тоже выведетFalse).Вот пример, почему такое его использование приведет к проблемам:
Заголовок спойлера
Не понятно написал, попробую раскрыть мысль в этом комментарии. Я "подсадил" друзей и родственников на эти программы. Они, как раз, более чем обычные пользователи и 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. Но можно сделать еще лучше:Заголовок спойлера