Comments 175
Ну и где плашка о том, что это перевод? Ну не мог шарящий человек скопировать сниппеты кода без отступов и писать "НП" вместо "UB".
А по поводу отступов, чисто вот сам сталкивался, если текст набираешь в ворде, то потом он копирует без отсупов. Обычно держу отдельный тектовичок для кода. Просто потом при вёрстке лениво доправлять бывает. Буквально со своей последней трилогией так накололся.
Преимущества Rust не ограничиваются безопасным доступом к памяти, есть ряд других полезных свойств, которые могли бы облегчить труд разработчиков ядра Linux. Взять хотя бы инструментарий для управления зависимостями. Много-ли тех, кому по душе сражаться с include путями в заголовочных файлах, раз за разом запускать pkg-config вручную, либо через макросы Autotools, полагаться на то, что пользователь установит нужные версии библиотек?
эээ… как говорится, где ядро linux, и где autotools?
Лично для меня внедрение нового языка, тут же превратит элегантный код ядра в мурзилку.
Clang делает тучу проверок, никак не прописанных в стандарте языка: например, кидает ворнинг на присваивание вида
if (a = b) /*...*/ ;
Предупреждение глушится парой дополнительных скобок:
if ((a = b)) /*...*/ ;
Мне не кажется, что из-за подобных проверок Clang перестаёт быть компилятором C.
Есть такие вещи, как MISRA C и Checked C, которые устраняют большинство проблем:
Но они никак не помогают при написании асинхронного кода
В плюсах есть корутины. В Си надо читать мануал: https://www.gnu.org/software/libc/manual/html_node/POSIX-Safety-Concepts.html
https://developers.redhat.com/blog/2014/09/10/multi-thread-async-signal-and-async-cancel-safety-docs-in-gnu-libc
В Си надо читать мануал:
Смысл Rust как раз в том, что конечному разработчику не нужно читать мануал — благодаря типам, тебе компилятор просто не даст сделать что-то неправильное.
И при этом всё будет легко читаться.
Много думать нужно только в ситуации, когда ты сам собираешься написать свой асинхронный рантайм.
Ну а C++ в ядре нет и не будет.
В Расте есть точно такой же ансейф код, и уж точно он не является никакой волшебной кнопкой, которая сделает тебе всё хорошо, даже если ты не прочитал ман. RTFM всегда RTFM. В системном программировании не бывает серебряных пуль.
У меня складывается впечатление из комментариев под каждым постом про раст, что это какая-то секта и религия, настолько всё восторженно и однотипно.
Фишка в том, что в C мануалы надо читать всем, а в Rust - только тем, кто пишет unsafe. Так-то да, безусловно, вообще без них не бывает, вопрос лишь в количестве.
вы явно кривите душой. не читая мануалов я сейчас даже hello world на rust'е не напишу.
хм, а зачем постоянно читать мануалы по си?
вы явно преувеличиваете. если не брать библиотечные функции, то ub не так уж много, и у всех понятно откуда ноги растут, если воспринимать си как переносимый ассемблер, то они неожиданностью не являются.
воспринимать си как переносимый ассемблер
Самый быстрый способ поймать UB. А некоторые чуть более продвинутые сишники этим еще и объясняют, почему в конкретном месте нет UB (конечно же чушь) и компилятор плохой (а вот тут согласен, ИМХО оптимизирующие компиляторы Си зло и мешают ему уйти
Самый быстрый способ поймать UB
можете проиллюстрировать?
И очень многие сишники, даже считающиеся опытными и компетентными, часто попадаются на том же, что если они пишут такой сишный код, они получат эдакий ассемблер, но это совсем не так в смысле абстрактной машины согласно стандарту, а значит и оптимизатора.
А почему вы не берёте библиотечные функции?
потому что в контексте написания ядра они неактуальны
В ядре Linux не переиспользуют чужой код? Я слышал обратное, но даже если это и так — пора это менять.
не понимаю как из «не используют библиотечные функции» вы вывели «не переиспользуют чужой код».
мы говорили о перечитывании стандарта языка си, в этом контексте «библиотечные функции» однозначно трактуются как C standard library, других в стандарте нет.
и да, эта libc из kernel space недоступна, надо обходиться без неё.
Мануалы по Rust - естественно, нужны, как и с абсолютно любым другим языком (там, где они не нужны для написания кода, они становятся нужны, когда - не "если" - этот код ломается; JavaScript тому живым примером). Вопрос был изначально, насколько я понял, не об этом, а о том, чтобы знать детально все правила по безопасной работе с нижележащими компонентами, которые в C должны быть учтены на всех уровнях, а в Rust, если их учесть на нижнем уровне, выше они будут выражены в виде проверяемых компилятором ограничений.
Как ты собрался писать ядро ОС без Unsafe? Этот пост про линукс кернел.
Если не хочешь читать мануалы, пиши на интерпретируемых языках. Хотя рано или поздно и там придётся погружаться в подсахарные горы.
Так это поэтому для Rust нет нормальных мануалов по структурам данных? Потому что они все требуют unsafe?
И все хавают этот ублюдский синтаксис
Мне даже интересно стало -- а как, собственно, Раст (да и вообще любой язык программирования) может устранять проблемы в логике программы? Или помочь их устранить?
В статье примеры проблем перечислены. Большинство искусственные, конечно. Но когда это останавливало разработчиков новых прекрасных языков программирования? За Linux вот только страшновато. Обычно софт на Rust выходит корявым логикой своей работы, потому что Rust уж слишком ограничивает выразительные возможности.
Мой любимый пример - реализация двусвязного списка на Rust. Даже на Haskell это проще сделать.
Ну, допустим, вы его реализуете. А зачем? В какой практической задаче он будет значимо эффективнее обычного вектора?
И чем это лучше реализации на Си? Unsafe-код есть, ручное управление памятью есть, потокобезопасности нет. ??♂️
С точки зрения тех, кто его реализует, - ничем. Возможно, даже хуже, потому что им надо учитывать те вещи, которые при реализации на Си можно было прописать в документации и понадеяться на разумность использующей стороны.
И чем это лучше реализации на Си?Хотя бы тем, что это в стандартной библиотеек языка, готовое, протестированное, даже с некоторыми гарантиями (ведь rustc проверяет и unsafe блоки). Встречный вопрос: чем это хуже реализации на Си (кроме потенциального «это написано мной, поэтому оно лучше по определению»)?
Потокобезопасность — вообще не связанное со списками понятие, даже обычные int / i32 — не потокобезопасные. Кстати, Rust не даст вам предать потоко-опасные (без реализации трейта Sync) переменные в соседний тред, всё завершится ошибкой сборки, если нужна многопоточность — оборачивайте в Arc<Mutex<>> или что-то аналогичное. А что там в C?
Система типов в Rust - unsound, и допускает ошибки, а сам проверяльщик с багами. Поэтому эти проверки 100% гарантий не дают.
Про библиотеку не понятно. Мы же говорим о программировании в Linux, так ведь? В ядре есть библиотека примитивов. Она тоже протестирована, гораздо лучше, кстати, чем Rust, и тоже даёт гарантии.
Си лучше тем, что он не даёт ложных обещаний корректности программисту, и программист думает, когда пишет код, отлаживает и тестирует экзотические и паталогические поведения.
В Rust программист борется с системой типов, обычно, полагаясь на неё. Н,о на самом деле, гарантий никаких нет. Вы загрузили два драйвера в ядро, что будет гарантировать, что они не используют одну и ту же очередь, без Sync? Как компилятор это проверит? Кроме того, при тестировании нельзя создать паталогические сценарии, потому что система типов и структуру тестов ограничивает - снова нужен unsafe или ffi (unsafe в тестах, Карл!)
Что делать с обработчиками прерываний? И т.д. и т.п. Вопросов много, а ответ один: unsafe. Ну и зачем такое счастье?
Вот, например, понятно, зачем вкорячивать Lua в ядро NetBSD: дополнительная гибкость и скорость разработки. Зачем вкорячивать Rust в Linux - я не понимаю. Это только повысит трудоёмкость разработки, но ничего не даст взамен (везде будет unsafe из-за специфики ядер операционных систем).
Это хуже, потому что там бывают весьма серьёзные протечки: из стека в static, например. В Си вы знаете, что так может быть, и следите за этим, структурируете программу соответствующим образом. В Rust вы верите, что так не бывает, и не следите, а потом долго удивляетесь, что вам сносит стек. При этом, опасное поведение может быть запрятано в библиотеке.
Rust даёт обещания, которые не выполняет, и полагаться на него нельзя. Всё равно, приходится прогонять всё через valgrind какой-нибудь. Так зачем тогда Rust?
обычные int / i32 — не потокобезопасные. Кстати, Rust не даст вам предать потоко-опасные (без реализации трейта
Sync) переменные в соседний тред, всё завершится ошибкой сборки, если
нужна многопоточность — оборачивайте в Arc<Mutex<>> или
что-то аналогичное. А что там в C?
В С есть cmpxchg.h
Не знаю как в расте, всё руки не доходят посмотреть на него, действительно ли он не даст передать потоконебезопасные, обычные i32 в соседний тред, и как концепция тредов будет работать в ядрёном контексте, где тред-то по сути один, а критическую секцию создают асинхронные события или обработчики, например, прерываний. Но лучше бы давал, потому что синхронизация через cmpxchg помогает с быстродействием. М.б. уточнение про трейт Sync это схожая конструкция.
Заменителем cmpxchg.h в Rust являются атомики. Берёте AtomicI32 и передаёте по ссылке в столько соседних тредов сколько пожелаете. Компилируются что cmpxchg, что атомики в одни и те же инструкции процессора, так что...
Что же до работы концепции тредов в контексте ядра — то вопрос что считать границей тредов оставлен на разработчика системного API. Сюда и асинхронные события без проблем попадают, и прерывания. Но да, есть и недостатки такого подхода — невозможно отделить, к примеру, понятия thread-safety, signal-safety и interrupt-safety, поскольку трейтов Send/Sync всего два (а надо бы шесть).
В ядре операционки. На уровне приложений вам эффективное изменение размера вектора обеспечивает виртуальная память - remap всякий. В ядре такой роскоши нет, а необходимость поддерживать fifo порядки есть. На самом деле, нужны более сложные структуры данных с переменным количеством элементов. Но если в Rust даже простая очередь - это небольшой unsafe адок, то что говорить о более сложных конструкциях?
То, что я увидел в статье, должно отслеживаться статическими анализаторами кода, как тот же PVS Studio. Изобретение нового языка для этого не требуется.
учитывая, что вы бегаете по комментам и ноете про плюсики-минусики :]
А я-то тут при чём? Вы безосновательно обвиняете меня в том, чего нет. Прошу извинится за свои слова, можете просмотреть все комментарии мои за пол года.
Переход на личности (argumentum ad hominem) — распространённый в Интернете (в частности, в Википедии) демагогический приём, подразумевающий дискредитацию аргументации оппонента посредством дискредитации его и/или его действий, а также провоцирующий некорректную ответную реакцию оппонента (в этом смысле переход на личности является формой троллинга).
Стыдно, товарищ, стыдно. Безосновательные обвинения.
Мне не хочется ссорится с вами, скатываясь в переброску обвинений (которые бессмысленны). Конкретно в данном случае, мне показалось что автора комментария безосновательно минусят, и допускаю, что эпитеты которые я подобрал были не очень корректными.
Но, мне правда неприятно, что вы оговариваете меня в том, чего реально нет. Давайте не будем разводить токсичность на данном ресурсе, мы в одной лодке.
Тогда мне, пожалуй, стоит переформулировать на "а как, собственно, Раст (да и вообще любой язык программирования) может устранять ошибки в логике программы?"
Да ладно? Проекты на Си обмазывают тестами, фаззерами, разнообразными статическими анализаторами весьма обильно. Инструментов для этого предостаточно.
Не знаю. Но прелесть в том, что это можно сделать независимо от авторов проекта. Если нужно, вы берёте, например, libpng, дописываете спецификации какого-нибудь Farma-C, и проверяете. И для этого не нужно ограничивать выразительность исходного языка.
А что делать? Ждать, когда эти десятки тысяч либ перепишут на Rust? Так, ведь, никогда не перепишут. Проблема Rust в том, что он просто не позволяет реализовывать некоторые алгоритмы в safe-режиме. А менять unsafe C на unsafe Rust не особо экономически оправдано. Поэтому, да, проще взять и проверить критически важные библиотеки на C. Собственно, все так и делают, кому безопасность важна.
Да, да, конечно. Именно NIH-синдром. И у каждой компании собственный компилятор Си... Не поэтому людям Rust не заходит, совсем не поэтому. Ещё раз повторю: нельзя на safe Rust закодировать некоторые алгоритмы. А дальше вопрос: зачем на Rust переходить, если будет, всё равно, unsafe? Просто, потому что модно, что ли?
Не правда. На практике unsafe используется даже в коде тестов, потому что без unsafe не триггернуть некоторые поведения. И смотреть надо не на то, сколько по объёму этот unsafe занимает, а на какой код он влияет, и там уже будет точно не 1%. В Rust могут быть крайне мозголомные утечки даже без unsafe, а с unsafe можно нарушать любые гарантии.
В Си, мы знаем, что можем снести себе ногу, и работаем осторожно, структурируем программы так, чтобы минимизировать риски. В Rust вы можете просто не знать об ошибке: компилятор съел код, и точка, вы верите, что всё хорошо. Народ, ведь, именно так и программирует: не через дизайн системы, а через затыкание компилятора. Смотрите на кучу unwarp повсеместно во всём коде на Rust. Это существенно снижает качество ПО, а не повышает.
Смешной анекдот - это реализация Redox.
Не язык виноват, что на нём пишет криворукий. Безопасность прежде всего должна обеспечиваться тем, кто пишет код. Компилятор и тулзы это уже вторично. Как бы не получилось так, что Rust продвинет тему безопасного кода, где первичен компилятор.
вы неверно истолковали мой посыл. исключать "правила дорожного движения" нельзя. они должны подстраховывать, но не стать страховкой
при наличии этих правил, неумеющий ездить и полагающийся только на инструктора, не лучший участник движения.
Если бы все ездили только по правилам, аварийность была бы гораздо выше. Иногда приходится совершать запрещённые манёвры, чтобы избегать столкновений. В крупных городах приходится делать это довольно часто.
При движении на мотоцикле, так и вообще правила соблюдать небезопасно. Например, гораздо безопаснее двигаться в междурядье, а не по полосам движения, чтобы быть заметным в зеркалах заднего вида автомобилей.
Кроме того, аналогия плохая. Правила - для людей, а не для машин. Это как code style, а не как borrow checker. И правила довольно часто пересматривают, чтобы адаптироваться к новым реалиям. Про borrow checker такого не скажешь, адаптивностью он не отличается.
Все правильно написали. Замечу лишь, переход на раст с другого языка для повышения безопасности видится правильным решением. Вхождение через раст в программирование, расхолаживает и привьет плохой подход. Зачем думать о безопасности, подскажет ведь в случае чего.
кто начал с раста, придя в питон, сломается. ведь теперь надо думать, чтоб не передать строку в функцию с числом
Кроме Rust есть множество безопасных языков программирования, которые позволяют работать со сложными структурами данных без необходимости пересекать границу unsafe. Тем, кому нужна безопасность, идут в эти языки, и пишут большую часть кода на них, оставляя только небольшие чувствительные к производительности участки для реализации на языках с более слабыми гарантиями безопасности. Но это небольшие участки кода, нет никакого смысла использовать для них такой громоздкий язык, как Rust, в котором они были бы, всё равно, реализованы unsafe.
Ядро ОС таким образом не напишешь. А если напишешь - то и на Rust точно так же получится: часть, которая раньше писалась бы на C, пишется в точно таком же стиле на unsafe Rust, всё остальное - #![forbid(unsafe)]
.
Rust не производительнее C - я скидывал ссылку на сравнение в реальной задаче, и не безопасный - его система типов unsound и допускает ошибки и утечки памяти. Кроме того, любой мало мальски нетривиальный алгоритм требует использования unsafe для работы со структурами данных. Если бы Rust позволял писать работу со сложными структурами в safe, вопросов бы к нему не было, всё было бы супер. Но не позволяет же. Ковырни любую библиотечную структуру данных - там врутри unsafe код. А с учётом того, что система типов Rust некорректна (правда, мы не знаем, она математически некорректна, или это косяки реализации, но тем не менее, в текущем состоянии она допускает утечки памяти), unsafe для любой нетривиальной структуры данных - это вдвойне неприятно. Не понятно, где произойдёт выстрел в ногу.
Ладно бы это было только в недрах операционки, но, ведь, в unsafe возникает необходимость просто в обычном пользовательском коде.
Вы сами давали ссылку на реализацию очереди на Rust, которая длинее в 20 раз, чем реализация на С - это громоздкость. Если не нравится C, то можно взять Go (теперь мне не нравится, ну, да ладно). Тоже будет короткая простая реализация без урезанной функциональности. И производительность у Go вполне на уровне. Rust без unsafe от Go сильно оторваться не может:
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/rust-go.html
Так зачем при прочих равных мне выбирать более сложный язык программирования? Чтобы что?
любой мало мальски нетривиальный алгоритм требует использования unsafe для работы со структурами данных.Интересно, а вы открывали binary-trees Rust #5? Судя по этому примеру, Rust не только позволяет безопасно (да, там нет unsafe) создавать структуры данных сложнее массива, но даже работает быстрее чем С? Неужели вы сами скинули ссылку, опровергающую ваши же доводы о немощности safe Rust?
она допускает утечки памятиА Rust и не гарантирует отсутствие утечек памяти, его safety нацелена на устранение того, что в C является undefined behavior: out-of-range чтение и запись, использование неинициализированной памяти, use after free, double free. Грубо говоря, Rust борется с тем, чтоб ваша программа не упала из-за недосмотра или опечатки. Логические ошибки, утечки памяти и даже дедлоки — это неприятно, но они не заставляют ядро пристрелить ваш процесс на месте (а если бы заставляли — программисты на C взвыли бы 50 лет назад). Разработчики языка такие проблемы не признают unsafe, и их можно создать в safe-подмножестве. Если вам прям хочется, чтоб память утекла — не ходите далеко, используйте функцию leak.
На практике unsafe используется даже в коде тестов, потому что без unsafe не триггернуть некоторые поведения.
А можно, пожалуйста, предъявить доказательства этому заявлению? А то звучит, как наглый пиз наглая намеренная ложь.
Угу, unsafe
там — из-за from_raw_fd
, который в принципе не может быть безопасным, поскольку файловый дескриптор фактически просто число, и нет гарантии, что некое наперёд заданное число действительно отвечает какому-то файлу. Вызывать же её приходится из-за того, что openpty
из крейта nix — тонкой обёртки над API unix-like операционных систем — возвращает пару файловых дескрипторов.
Короче, не убедили.
он просто не позволяет реализовывать некоторые алгоритмы в safe-режимеСильное заявление. Мне даже интересно, почему (на ваш взгляд):
- эти некоторые алгоритмы не являются вычислимыми
- safe-подмножество Rust не является полным по Тьюрингу
safe-подмножество Rust не позволяет «красиво» реализовывать некоторые алгоритмы — возможно, но встаёт другой вопрос: что такое «красиво», как это померить, как сравнить с другими языками? И как быть с примерами, когда на safe Rust какой-то алгоритм реализовали «красивее», чем на том же С?
Ещё раз повторю свой вопрос: покажите safe-реализацию очереди на Rust. Вопрос не об абстрактной полноте, а о совершенно конкретных алгоритмах и структурах данных.
Я, конечно, понимаю, что теоретикам от терий типов безразлично, будет очередь O(1) или O(n), но на практике, особенно при программировании ядра OS, это чертовски важно
Если было бы важно, дизайнили бы Rust иначе. Вопросы представления структур данных и алгоритмов при разработке явно не на первом месте были.
И это, в принципе, ok. Это имеет право на существование. Это интересно. Если бы не эта вся агрессивная pr-компания по пропихиванию Rust во все места... Довели бы до ума Redox, написали бы manual: классические алгоритмы и структуры данных на Rust - было бы хорошо, люди бы потянулись. Может быть, надо сначала научиться нормально, не через хэши, кучу Фибонначи реализовывать, и только потом уже в ядро лезть?
Но, ведь, нет. Нам втирают без каких либо достоверных обоснований, что это better C. Но по исходникам Redox и Servo видно, насколько better: Rust - очередная итерация "the worse the better".
Вы говорите об аналоге обычной std::queue? Тогда что-то вида
struct Node<T> {
data: T
next: Refcell<Rc<Node<T>>>
parent: Refcell<Weak<Node<T>>>
}
struct Queue<T> {
Option<Node<T>> head;
}
Правда, тут будет O(n) front(), чтобы сделать константным, наверное, надо делать
Option<Refcell<Node<T>>> head
Option<Refcell<Node<T>>> tail;
А реализация операций? С нетерпением жду.
Вот, держите: ссылка на полный код. Там есть тесты, которые успешно выполняются.
Да что же любители Rust такие поверхностные-то? Там прямым текстом в коде написано, что нельзя пройти по списку без его разрушения. Нельзя взять элемент из середины. Да и читал я этот блог, когда пытался что-нибудь более или менее работоспособное на Rust написать.
Да, он сложный. Это сложный код, который не решает тривиальную задачу. В операционке гораздо гораздо всё сложнее со структурами данных. Соответственно, код будет распухать, скорость разработки будет падать, функциональность будет страдать. Производиельность тоже, потому что это всё нифига не бесплатно. Можете сравнить ассемблер реализации на Rust и аналогичной реализации на Си. Не, конечно, если цель сделать разработку Linux более дорогой и недоступной широкому кругу любителей, а сам код более ресурсоёмким, то верной дорогой идёте, товарищи! Только вот будет ли такой Linux Linux-ом? Надеюсь, будет создан какой-нибудь stainless fork.
Компиляторы давно умеют анализировать псевдонимы, и хорошо их видят. Кроме того, есть restrict, если компилятору нет доверия.
Не очень понятно, откуда в рассуждениях взялся void со звёздочкой.
Какая практика? Можно подробнее?
В экосистеме C, если и делают обобщённые структуры данных, то не через void*, а через макросы -- жаба же давит указатель лишний раз разыменовывать. Но такая потребность возникает редко, потому что на Си обычно пишут узкоспециализированные утилиты и библиотеки, в которых нет особого простора для обобщений.
Держите вашу очередь:
pub struct Queue<T>
{
list: std::collections::linked_list::LinkedList<T>,
}
impl<T> Queue<T> {
pub fn new() -> Self {
Self {
list: Default::default(),
}
}
pub fn enqueue(&mut self, item: T) {
self.list.push_back(item)
}
pub fn dequeue(&mut self) -> Option<T> {
self.list.pop_front()
}
pub fn peek(&self) -> Option<&T> {
self.list.front()
}
}
(оставляя в стороне вопрос зачем) Теоретически -- вот: https://github.com/thepowersgang/mrustc
Есть такое https://github.com/Rust-GCC
https://drewdevault.com/2019/03/25/Rust-is-not-a-good-C-replacement.html
TLDR: нет, не нужен.
Как минимум, топик написан 3 года назад, и некоторые моменты не актуальны.
C is the most portable programming language.
Rust портативен ровно на столько, на сколько портативен LLVM (а в будущем и GCC, если rust-gcc станет стабильным)
В принципе для разработки драйверов для ядра Linux совершенно не обязательно поддерживать абсолютно все архитектуры, какие существуют в природе.
C has a spec
Компилятор и тесты на обратную совместимость — наиболее полная спецификация.
Цена спецификации нулевая, если разные реализации привносят свои уникальные фичи, или не полностью реализуют фичи из спецификации.
В целом сообщество признаёт эту проблему и когда-нибудь полноценная спецификация будет, но сейчас есть более приоритетные задачи.
C has many implementations
Rust-GCC. В целом «много конкурирующих реализаций» не могут быть преимуществом сами по себе.
Есть целая куча активно используемых ЯП, которые не имеют альтернативных реализаций.
Ну и Linux, на сколько я помню, не предполагает работу с десятками разных компиляторов.
C has a consistent & stable ABI
Эта проблема официально признана, но пока язык активно развивается — стабильный ABI это развитие остановит.
Если нужен стабильный ABI — всегда можно сделать extern «C» или использовать какой-нибудь другой ABI (wasi например)
Ну и разработке драйверов это не мешает.
Cargo is mandatory
Нет, cargo не обязателен, хоть и не рекомендуется работать без него (лично я не вижу ни одной причины отказываться от cargo).
В целом никто не запрещает использовать rustc и строить свою экосистему пакетов и инструментов.
Ну и это также не является больной проблемой ни для разработки ядра, ни для Embedded.
Concurrency is generally a bad thing.
«У каждого инструмента есть свои особенности, и свои задачи».
Вроде у нас сейчас 2022 год, а значит в компьютерах у нас многоядерные процессоры. А значит, если мы хотим сделать что-то, что будет эффективно использовать все имеющиеся ресурсы — придётся всё равно уйти в конкурентность. Не важно в каком виде.
Rust не обязывает писать конкурентный код, и защищает твои ноги, если вдруг тебе нужно будет работать с общим состоянием.
Си не запрещает писать конкурентный код, и не даёт тебе никаких инструментов для защиты.
Ну и тут автор просто делает реверанс в сторону Go и его горутин и каналов, думая что это не конкурентный код.
Ну и да. Ядро Linux одна из таких программ, которая не может обойтись без параллельного или конкурентного программирования.
Safety.
Тут автор вообще говорит «я не тупой, я сам могу всё учесть, чтобы не получить segfault».
Так что аргумент не аргумент.
Фундаментальная суть проблемы раста описана там в последнем параграфе. И изменить её невозможно ни за пять, ни за 10 лет, потому что это сама философия языка. Тут потребуется написать другой язык.
C is far from the perfect language - it has many flaws. However, its replacement will be simpler - not more complex. Consider Go, which has had a lot of success in supplanting C for many problems. It does this by specializing on certain classes of programs and addressing them with the simplest solution possible. It hasn’t completely replaced C, but it has made a substantial dent in its problem space - more than I can really say for Rust (which has made similar strides for C++, but definitely not for C).
The kitchen sink approach doesn’t work. Rust will eventually fail to the “jack of all trades, master of none” problem that C++ has. Wise languages designers start small and stay small. Wise systems programmers extend this philosophy to designing entire systems, and Rust is probably not going to be invited. I understand that many people, particularly those already enamored with Rust, won’t agree with much of this article. But now you know why we are still writing C, and hopefully you’ll stop bloody bothering us about it.
Насчёт Go, который «has made a substantial dent in its problem space»: основные преимущества Go — быстрое написание кода и простое распараллеливание => в основном микросервисы и микроутилиты. Go в основном отобрал долю рынка у других языков (типа Python), но не у C — ни микросервисы, ни приложения типа «два раза запущу и забуду» на C редко пишут. Даже если почитать «истории успеха перехода на Go» — почти везде будет переход с Python.
Го там был дан в пример не как пример системного языка, а как пример философски правильно спроектированного языка, вследствие чего занявшего доминирующее положение в своей нише, дальше которой разрастаться и замусориваться не хочет. Чего нельзя сказать о Расте. Проблема Раста, на мой взгляд, это вообще больше даже не проблема техническая per se, а, скорее, вопрос конфликта отцов и детей. Новое поколение считает, если что-то создано 30-40 лет тому назад, оно по умолчанию не может быть хорошим. Просто вот так вот. Хорошо хоть, аксиомы планиметрии пока держатся иммутабельно.
что-то создано 30-40 лет тому назад, оно по умолчанию не может быть хорошимОно может быть всё ещё хорошим, но за эти 30-40 лет придумали немало новых других хороших штук, поэтому более современные языки не хуже. В случае с тем же Rust — появились проверки на типовые выстрелы в ногу, принудительные. В C сделать, например, buffer overflow вообще элементарно (особенно если работать со строками) но узнаете вы об этом когда будет уже поздно. Да, C-код будет работать чуть-чуть быстрее (возможно), но вам придётся писать существенно больше кода (потому что язык старый и в нём нет мощных конструкций типа match), и у вас будет сильно меньше гарантий, что оно не упадёт из-за какой-нибудь глупой ошибки.
А уж как приятно отлаживать макросы в чужом коде на C, ммм…
Go предназначен для написания больших распределённых по сети систем, типа Kubernetes или просто каких-то сервисов.
А Си предназначен больше для работы с каким-нибудь лоу-левелом, как при разработке операционных систем или embedded
Я довольно хорошо осведомлён о том, что чувствует коммьюнити в целом по отношению к системным языкам, и у меня сложилось впечатление, что все хором сильно топят за Зиг, а вот с Растом ситуация очень divisive -- половина его ненавидит, половина превозносит.
OSи пишут на разных языках: Lisp, Java, Haskell, Forth, ML и даже JavaScript. Написать небольшую OS для конкретной железяки - не такой уж и амбициозный проект. У меня второкурсники микроядра с вытесняющей многозадачностью писали за месяц. Человечество уже давно знает, как это делается. В этом плане Rust ничего принципиально нового не предлагает...
Ну, разве только то, что не получится привычные структуры данных использовать для всяких очередей таймеров или планировщиков пакетов. В этом есть некое интеллектуальное приключение. Но что-то я сомневаюсь, что оно упрощает написание OS, а не усложняет. В той же Redox довольно печально с этим дела обстоят: вместо кучи таймеров активное ожидание с переключением контекстов, очередями событий служат deque и т.д. Не самые эффективные решения, мягко говоря, особенно для систем реального времени.
Redox по-моему всё, умер.
Типа, не смогли сделать Redox, поэтому пришли в Linux? Опасные ребята...
Нет, всё-таки, месяц назад был релиз: https://www.redox-os.org/news/release-0.7.0/
C has a spec
Добавлю: если уж говорить о разработке Linux, то там используется особый диалект Си (GCC Си с особыми флагами), который точно также не имеет нормальной спецификации.
Во-первых, это Дрю. И если для вас это не является красным флагом, то мне вас жаль.
Во-вторых, вся эта стена текста разбивается в пух и прах двумя предложениями в конце:
Yes, Rust is more safe. I don’t really care.
Учитывая, что это только один пункт из семи перечисленных, после которого идёт "In light of all of these problems", нет не разбивается, и вырывать куски из контекста это, мягко говоря, некорректно.
При примате safety я бы выбрал Аду, а не раст -- как разработчики NASA.
А почему Дрю должен быть красным флагом?
Потому что у него очень свои взгляды на разработку софта, зачастую неправильные. И у него есть софт, которым пользуются люди, только больно падучий почему-то.
Потому что у него очень свои взгляды на разработку софта, зачастую неправильные
Ну взгляды действительно свои и специфические, только взгляды - они не могут быть неправильными, они у каждого свои. Они могут не совпадать с вашими, но они не становятся неправильными.
По сути же да, они радикальные, тем не менее дают какие-то ценные инсайты, про то как снять ментальную нагрузку при разработке.
В контексте этой темы я практически со всем согласен, что Rust радикально более сложный язык, и для системного программирования пока нет чего-то более подходящего, чем C с достаточно широким внедрением.
И у него есть софт, которым пользуются люди, только больно падучий почему-то.
А что вы имеете в виду? Sway?
Учитывая, что Sway и wlroots пользуются тысячи человек, это так себе аргумент, даже не принимая во внимание, что ad hominem. На расте проектов масштаба того, что пишет Деволт, я не знаю. Можно было бы назвать фаерфоксовский Servo, но и его пилили-пилили, да так и не допилили.
Так как раз ОСы на нём писать крайне неудобно. В этом-то весь цимес. Он слишком ограничивает.
Cloudflare uses Rust in their core edge logic and as a replacement for C, which is memory-unsafeНо какие же разработчики Cloudflare балбесы, ведь в Rust нет безопасного двусвязного списка, зато есть сплошные ограничения на каждом шагу, а проверки могли бы и сами написать /s
В этой сфере важна стандартизация ISO, поэтому или Си, или Ада. Пока раст не будет стандартизирован, индустрия не будет в нём заинтересована.
Нет, не наоборот. В авиации, космической промышленнности, автомобилестроении, медицине и других сферах, где цена ошибки действительно велика -- Cloudflare к таковым не относится -- не будут использовать язык без стандартизации никогда.
По-разному бывает. Си просто стал стандартом де-факто, и после этого был стандартизирован. Ада специально заказывалась Министерством Обороны США под их нужды. В случае раста помимо низкого проникновения в индустрию мешает то, что язык как таковой ещё не финализирован самими авторами, он всё ещё work in progress.
В HFT, которые известны мне, используют Скалу, Кложу и Окамл. Это другая область. Сейчас, может, и на раст стали смотреть.
Их это не смущает, значит, это не такая большая проблема, как кажется. Видимо, функциональная парадигма важнее с её проверками корректности.
Я не трейдер, но насколько мне известно, то, чем занимается Jane Street, это именно HFT, у них окамл.
Это вполне HF. Во-первых, есть специальные сборщики с низкими задержками. Во-вторых, в HFT работа ведётся с несколькими постоянно живыми массивами историй. Работа, в основном, арифметическая, объектов в куче почти нет, нагрузка на GC низкая. Поэтому даже Clojure достаточно быстр для торговли с частотой 1ms при обработке нескольких сотен тысяч записей в истории. Был доклад на Clojure Conj несколько лет назад об этом.
Пора, пора уже Торвальдсу сделать с этой помойкой под названием Linux что нибуть такое, что бы народ начал массово пересаживаться на *BSD.
FreeBSD is the way Linux had to be. (C) народная мудрость.
Rust и Linux