История изменений
Исправление byko3y, (текущая версия) :
Разве я предлагал заменять джаву/C# на раст? На С и С++ пишут весьма большие проекты без сборки мусора
Если ты про ядро линя или про оракл, то расту там особо нечего ловить. Например, как ты собрался реализовывать работу с RCU на расте? И то же самое относится к любому lock-free, которого в ядре ОЧЕНЬ много. Раст подходит в качестве «языка скриптинга», как для ОС, так и для БД, то есть, дергать отдельные безопасные функции для кастомизации обработки, вроде драйверов или функций БД. За этими границами ты получаешь просто один сплошной unsafe, а если у тебя хотя бы треть кода является unsafe, то safe-unsafe вообще теряет смысл, ведь ты полностью теряешь возможность отслеживать потенциально опасные участки кода через unsafe и непосредственно связанные с ними, потому что в эту категорию попадает почти весь код, а оставшаяся чисто safe часть ничтожна.
Ансейф - это просто явный маркер. Да, это не единственный критерий (код с супер-важной бизнес-логикой может быть без unsafe), но зато он хорошо формализуется
Вот я недавно снова писал на крестах, вспоминания про нашу беседу, и вывел более общую закономерность: бинарные safe-unsafe, private-public, nonconst/const НЕ РАБОТАЮТ ДЛЯ СЛОЖНЫХ СЛУЧАЕВ. Как только сложность становится чуть больше нуля, выясняется, что есть сложносплетенные объекты, которые имеют const интерфейс без константности всех внутренних объектов, что private поля нужно менять из других модулей, и, самое главное, что критериев «безопасности» кода сильно больше одного, есть понятия «безопасно, если...» и «некорректный указатель, но это пофиг, потому что мы все равно выбрасываем указатель». Да, Rust вводит еще и многопоточную безопасность передачи объектов, но я дам пример RW-блокировок, где этих бинарных маркеров снова недостаточно.
Можно увидеть, что бинарные маркеры придумали МЕНЕДЖЕРЫ, которые в своей жизни ничего больше тысячи строк не писали (и не читали). Логика менеджера: если нужно что-то исправить — давайте сделаем для этого новую фичу. Хорошо формулизируется, хорошо бюрократизируется — идея как бы правильна, вроде работает для примитивных применений, но она совсем не масштабируется (как я уже говорил, но про один только const). Сравни это с логикой грамотного архитектора: «что нужно выкинуть, чтобы система заработала?».
Недавно ковырял либу, где САМ АВТОР наступил на собственные грабли, будучи вынужденым через анус лезть к приватным полям своих собственных классов из другого модуля. Потому что для простой модели private/public прокатывает, но как только сущности начинают сплавляться друг с другом, то выясняется, что нужны либо прокладки (как принято в Rust), либо прямой доступ к полям. А я просто взял этот код и сделал все члены класса публичными и неконстантными. Сразу операторы заработали и стала возможной беспроблемная передача по ссылке. То есть, опять же «private, если...».
И самое смешное то, что небинарные vector<int>
, const vector<int>
, vector<const int>
, const vector<const int>
эту функцию тонкого контроля как раз не выполняют, а только мешаются, как третья нога. Как раз недавно пилил контейнеры, обматерил их не один раз, в очередной раз копипастя nonconst-const методы и прилепливая SFINAE касты контейнеров из nonconst в const — почему-то эти проблемы есть у всех, и даже у Мейерса, но не у тебя. Как я уже писал, либо у тебя очень специфичный код, либо ты их просто НЕ ЗАМЕЧАЕШЬ В УПОР.
Короче говоря, ты никогда не хотел private-public, const, unsafe, ты хотел сделать аккуратные интерфейсы для своих функций, но в используемом тобой ЯП есть только вот эти инструменты для организации интерфейсов. Интерфейсы, которые бы хорошо показывали на ревью, когда пользователь кода пользует штатные интерфейсы, а когда — лезет в кишки, обходя безопасные функции.
Но альтернативные походы есть — это, как ни странно, сишные непрозрачные указатели на структуры. Они убоги, да, но я просто хочу показать, что есть подходы к построению интерфейсов, которые выполняют одновременно функции private-public, nonconst-const, safe-unsafe директив, и при этом в них не используются данные директивы. Директив нет, а инкапсуляция есть — как так? Или паскаль, в котором есть ограниченная реализация RAII через частично непрозрачные структуры данных, полный доступ к которым, однако, при желании можно получить, и даже переписать стандартную реализацию.
Ты прав лишь в том, что при прочих равных я предпочел бы дергать либу, где автор уже налюбился с интерфейсами, где деклараций больше, чем логики внутри, где уже написан клей для взаимодействия со всеми возможными смежными типами, вроде каких-нибудь строк, которые в одном только STL могут быть представлены std::string, std::string_view, std::array, std::vector. Но я ни за что в жизни не полез бы по собственной воле пилить самостоятельно такую либу просто для того, чтобы Махеш или Ананда не завалили проект своим безалаберным говнокодом. А потом ты всё переписываешь с нуля, если требуются особые требования к аллокатору — та же STL часто превращается в тыкву из-за запрета на исключения и/или глобальные аллокации. И если ты много пишешь на крестах, то по-идее должен увидеть обе стороны монеты, но ты почему-то видишь только одну.
И еще один риторический вопрос: какого хера в Rust до сих пор нет RTTI?
Исходная версия byko3y, :
Разве я предлагал заменять джаву/C# на раст? На С и С++ пишут весьма большие проекты без сборки мусора
Если ты про ядро линя или про оракл, то расту там особо нечего ловить. Например, как ты собрался реализовывать работу с RCU на расте? И то же самое относится к любому lock-free, которого в ядре ОЧЕНЬ много. Раст подходит в качестве «языка скриптинга», как для ОС, так и для БД, то есть, дергать отдельные безопасные функции для кастомизации обработки, вроде драйверов или функций БД. За этими границами ты получаешь просто один сплошной unsafe, а если у тебя хотя бы треть кода является unsafe, то safe-unsafe вообще теряет смысл, ведь ты полностью теряешь возможность отслеживать потенциально опасные участки кода через unsafe и непосредственно связанные с ними, потому что в эту категорию попадает почти весь код, а оставшаяся чисто safe часть ничтожна.
Ансейф - это просто явный маркер. Да, это не единственный критерий (код с супер-важной бизнес-логикой может быть без unsafe), но зато он хорошо формализуется
Вот я недавно снова писал на крестах, вспоминания про нашу беседу, и вывел более общую закономерность: бинарные safe-unsafe, private-public, nonconst/const НЕ РАБОТАЮТ ДЛЯ СЛОЖНЫХ СЛУЧАЕВ. Как только сложность становится чуть больше нуля, выясняется, что есть сложносплетенные объекты, которые имеют const интерфейс без константности всех внутренних объектов, что private поля нужно менять из других модулей, и, самое главное, что критериев «безопасности» кода сильно больше одного, есть понятия «безопасно, если...» и «некорректный указатель, но это пофиг, потому что мы все равно выбрасываем указатель». Да, Rust вводит еще и многопоточную безопасность передачи объектов, но я дам пример RW-блокировок, где этих бинарных маркеров снова недостаточно.
Можно увидеть, что бинарные маркеры придумали МЕНЕДЖЕРЫ, которые в своей жизни ничего больше тысячи строк не писали (и не читали). Логика менеджера: если нужно что-то исправить — давайте сделаем для этого новую фичу. Хорошо формулизируется, хорошо бюрократизируется — идея как бы правильна, вроде работает для примитивных применений, но она совсем не масштабируется (как я уже говорил, но про один только const). Сравни это с логикой грамотного архитектора: «что нужно выкинуть, чтобы система заработала».
Недавно ковырял либу, где САМ АВТОР наступил на собственные грабли, будучи вынужденым через анус лезть к приватным полям своих собственных классов из другого модуля. Потому что для простой модели private/public прокатывает, но как только сущности начинают сплавляться друг с другом, то выясняется, что нужны либо прокладки (как принято в Rust), либо прямой доступ к полям. А я просто взял этот код и сделал все члены класса публичными и неконстантными. Сразу операторы заработали и стала возможной беспроблемная передача по ссылке. То есть, опять же «private, если...».
И самое смешное то, что небинарные vector<int>
, const vector<int>
, vector<const int>
, const vector<const int>
эту функцию тонкого контроля как раз не выполняют, а только мешаются, как третья нога. Как раз недавно пилил контейнеры, обматерил их не один раз, в очередной раз копипастя nonconst-const методы и прилепливая SFINAE касты контейнеров из nonconst в const — почему-то эти проблемы есть у всех, и даже у Мейерса, но не у тебя. Как я уже писал, либо у тебя очень специфичный код, либо ты их просто НЕ ЗАМЕЧАЕШЬ В УПОР.
Короче говоря, ты никогда не хотел private-public, const, unsafe, ты хотел сделать аккуратные интерфейсы для своих функций, но в используемом тобой ЯП есть только вот эти инструменты для организации интерфейсов. Интерфейсы, которые бы хорошо показывали на ревью, когда пользователь кода пользует штатные интерфейсы, а когда — лезет в кишки, обходя безопасные функции.
Но альтернативные походы есть — это, как ни странно, сишные непрозрачные указатели на структуры. Они убоги, да, но я просто хочу показать, что есть подходы к построению интерфейсов, которые выполняют одновременно функции private-public, nonconst-const, safe-unsafe директив, и при этом в них не используются данные директивы. Директив нет, а инкапсуляция есть — как так? Или паскаль, в котором есть ограниченная реализация RAII через частично непрозрачные структуры данных, полный доступ к которым, однако, при желании можно получить, и даже переписать стандартную реализацию.
Ты прав лишь в том, что при прочих равных я предпочел бы дергать либу, где автор уже налюбился с интерфейсами, где деклараций больше, чем логики внутри, где уже написан клей для взаимодействия со всеми возможными смежными типами, вроде каких-нибудь строк, которые в одном только STL могут быть представлены std::string, std::string_view, std::array, std::vector. Но я ни за что в жизни не полез бы по собственной воле пилить самостоятельно такую либу просто для того, чтобы Махеш или Ананда не завалили проект своим безалаберным говнокодом. А потом ты всё переписываешь с нуля, если требуются особые требования к аллокатору — та же STL часто превращается в тыкву из-за запрета на исключения и/или глобальные аллокации. И если ты много пишешь на крестах, то по-идее должен увидеть обе стороны монеты, но ты почему-то видишь только одну.
И еще один риторический вопрос: какого хера в Rust до сих пор нет RTTI?