Комментарии 19
Как написали в комментариях на OpenNet, "Вся ценность Rust свелась к одному заголовочному файлу для C++" и плагину для компилятора, причем после проверки исходного кода, плагин можно вообще не использовать, поскольку он только анализирует AST, но не вносит в него никаких изменений.
Разница в том, что в Расте borrow checker - это не опциональное удовольствие, "тут хочу, а тут не хочу". С безопасностью всегда так, иначе это не безопасность, а решето.
В Расте и все зависимости, и весь код проекта следует одним правилам управления памяти, и могут эту информацию передать в компактном, встроенном в язык виде. А на плюсы можно накручивать сверху парадигмы сколько угодно, вот только получается Франкенштейн, где у каждого проекта и библиотеки свои правила во всём
Так безопасность языка, это не цель, а только одно из множества требований к нему. Есть еще удобство разработки, совместимость, стоимость поддержки или перехода на новый язык и т.д. Тем более, что корректность исходного кода != корректное выполнение программы, и никогда не будет 100% гарантии в правильном выполнении приложения, хоть какой язык программирования не используй.
Так безопасность языка, это не цель, а только одно из множества требований к нему
Так подождите, "вся ценность Rust свелась к одному заголовочному файлу для C++" же.
Есть еще удобство разработки
Именно! И тут C++ проигрывает, потому что ownership получается надстройками, порой несовместимыми с зависимостями (даже unique_ptr
и тот не всегда используется).
совместимость
С чем? С экосистемой языка? Тут провал C++. С внешним миром (на всяких микроконтроллерах и freestanding target'ах) и FFI? Тут Раст проигрывает, ибо его неопциональная концепция безопасности не даёт разработчику стрелять в ногу, даже когда пули точно до ноги не долетят, тут только её очень многословно обходить окольными путями.
Корректность исходного кода != корректное исполнение программы
Ну знаете ли. 99% уверенности в правильности работы тоже неплохо /s
В идеальном мире программы или работают абсолютно правильно, или не работают вообще. К сожалению, наш мир не курс основ мат. логики; корректность работы программы это спектр. Баги (даже логические) далеко не всегда являются критичными, а требования часто могут быть адаптированы под реальную реализацию.
Раст устраняет целый класс весьма критичных ошибок - которые по невнимательности приводят к крашам и/или повреждению данных. Да, на Расте можно допускать баги. Да, программы на Расте неидеальны, даже если компилируются. Да, есть программы, которые помечают все функции как unsafe
и пожинают плоды. Но, при всём при этом, ошибок меньше. И это - хорошо. Никакие надстройки над C++, без полной переделки концепции, не приведут к такому результату; а если таки переделать, получится ещё один Раст, со всеми преимуществами и недостатками. Только с устаревшим синтаксисом, чтобы люди видели почти привычный Си там где его уже, в общем-то, нет.
Надеюсь вы понимаете, что слабые ссылки не бесплатные. И должно быть минимум 2 вида слабых ссылок: однопоточные и многопоточные. Первые почти бесполезные, вторые внутри реализованы через бесконечный цикл с atomic::compare_exchange_weak.
В Rust же концепция владения полностью zero-cost. Кроме того сильные/слабые ссылки сами по себе не предотвращают гонки данных.
Следует начать с того, что бесплатного вообще ничего не бывает, даже сыр в мышеловке, поэтому можно только сравнивать реализации с учетом связанного контекста.
Например, вы хотите сделать какую-то фичу полностью Zero-cost, например убрав реализацию под макрос, который удаляет лишний код при компиляции, но в этом случае вы перераспределяет трудоемкость (стоимость) такого решения за счет усложнения отладки и последующей поддержки такого кода.
В Rust небесплатность заключается в том, что нужно указывать явно время жизни когда компилятор не может его вывести автоматически. Я вот сейчас посчитал, в текущем проекте на 50+KLOC таких строчек ровно 71 (0,14%), и это Embedded (микроконтроллеры STM32). Так что на практике отладка и поддержка не страдают.
Вообще я думал, что в С++ стараются избегать рантайм проверок (из-за чего в языке существуют многочисленные и неочевидные UB), а тут предлагается прямо противоположное.
Вероятно этот подход со слабыми ссылками будет по производительности даже хуже современного GC с аренами. Так не проще ли взять любой современный язык с GC и JIT?
P.S. В любом случае для С, С++ и Rust zero-cost проверки должны быть приоритетнее рантайм проверок, но мой взгляд.
В Rust платность заключается в необходимости переписывать тонны существующего кода и это никак не связано с рантайм проверками. Причем некоторые из таких проверок (например контроль циклических ссылок у динамически создаваемых объектов) при компиляции сделать невозможно (либо мне не попалось формальное доказательство этого).
Поэтому некоторые проверки всегда будут выполнятся в рантайме не зависимо от языка программирования. Из-за чего проще и дешевле переработать уже существующий код, чем переписывать его полностью без каких либо гарантий, что этот код не придется переписывать еще раз в будущем.
В Rust платность заключается в необходимости переписывать тонны существующего кода и это никак не связано с рантайм проверками.
Вы это сами только что придумали? Приведите цитату, где я предлагал что-то переписать на Rust!
Поэтому некоторые проверки всегда будут выполнятся в рантайме не зависимо от языка программирования.
Вот именно что некоторые проверки, причем довольно редкий случай для прикладного кода. А все прочие вы предлагаете сделать в рантайме вместо compile-time.
И я заметил как вы аккуратно забыли тему гонок данных и других UB, которые никак не предотвращает Memsafe, но предотвращает Borrow Checker, который вам так не нравится. Ведь вы изначально утверждали так:
Вся ценность Rust свелась к одному заголовочному файлу для C++
Приведите цитату, где я предлагал что-то переписать на Rust!
Разве под словами "Так не проще ли взять любой современный язык с GC и JIT?" не предполагается именно "переписать"?
Вот именно что некоторые проверки, причем довольно редкий случай для прикладного кода. А все прочие вы предлагаете сделать в рантайме вместо compile-time.
Вы спорите со своим собственным утверждением, которое неверно. С чего вы это взяли-то что в рантайме? Плагин работает именно во время компиляции.
... забыли тему гонок данных и других UB,
Не не забыл, но и не вижу смысла этот вопрос обсуждать, так как изначально решается совсем другая проблема. Borrow Checker в Rust решает кучу задач и это только одна из них. Но управление динамической памятью не связанная с гонками данных. Чтобы их не было, нужно использовать правильные классы и язык программирования тут не причем.
Ведь вы изначально утверждали так:
"Вся ценность Rust свелась к одному заголовочному файлу для C++", это цитата комментария с opennet и об этом я явно написал в самом комментарии
Разве под словами "Так не проще ли взять любой современный язык с GC и JIT?" не предполагается именно "переписать"?
Нет, не предполагается. Переписывать на другой язык может иметь смысл только если принято решение этот легаси в любом случае переписать.
Я имел ввиду новый код, думал что это очевидно.
Предложенная техника защиты походит на концепцию владения и заимствования из языка Rust, но реализована на базе сильных и слабых ссылок (стандартных механизмов С++ shared_ptr и weak_ptr). Любые операции с данными для переменной по ссылке возможны только после её захвата, т. е. после преобразования слабой ссылки (weak_ptr) в сильную (shared_ptr).
Вот этот абзац поста меня запутал, выглядит что всё происходит в рантайме. А у вас на гитхабе написано нормально, так что про рантайм я был не прав.
Чтобы их не было, нужно использовать правильные классы и язык программирования тут не причем.
Если язык позволяет и поощряет писать неправильно, будут писать неправильно. И не будут использовать "правильные классы", ведь без них код "как бы проще и короче". Об этом вам уже написали выше в этом комментарии.
"Вся ценность Rust свелась к одному заголовочному файлу для C++", это цитата комментария с opennet и об этом я явно написал в самом комментарии
Вы процитировали так, что полностью согласны. И выглядит это очень агрессивно, тем более что это неправда. А теперь вы резко поменяли точку зрения:
Borrow Checker в Rust решает кучу задач и это только одна из них.
Надо ещё проверить все ли виды ошибок ловятся этим самым Memsafe. А то документации на это чудо я вообще не нашёл, а потому что он так проверяет - неясно.
Переменные по значению и слабые ссылки могут копироваться из одной переменной в другую без каких либо ограничений.
Защищенная и ссылочная переменная могут быть скопированы только в локальные переменные более низкого лексического уровня или переданы в качестве аргумента в функцию при её вызове.
Запрещен возврат из функций защищенных и ссылочных переменных, которые были переданы в качестве аргументов или со счетчиком ссылок более единицы.
Запрещено сохранение захваченных значений как статических переменных.
Операция обмена значениями (swap) для защищенных и ссылочных переменных разрешены только между переменными одного лексического уровня.
https://github.com/rsashka/memsafe/blob/main/memsafe_concept.md
Интересно, а почему нельзя это делать без костылей? Почему опять должны страдать нормальные разработчики, а не говнокодеры? Ах да, комитет слишком занят обсуждением очередной нужной 3.5 корпораций херни
а зачем в таком случае дополнительные проверки делать если и так понятно что происходит? https://godbolt.org/z/Erv8bs3E9 https://godbolt.org/z/cvG7eoo1E
Релиз проекта Memsafe с механизмом безопасной работы со ссылочными типами и динамической памятью в коде для языка С++