Как стать автором
Обновить

Комментарии 174

Ну и где плашка о том, что это перевод? Ну не мог шарящий человек скопировать сниппеты кода без отступов и писать "НП" вместо "UB".

А что не так использовать аббревиатуру «Неопределённое Поведение» или «НП»?

А по поводу отступов, чисто вот сам сталкивался, если текст набираешь в ворде, то потом он копирует без отсупов. Обычно держу отдельный тектовичок для кода. Просто потом при вёрстке лениво доправлять бывает. Буквально со своей последней трилогией так накололся.

Это незнакомая аббревиатура, которая заставляет искать перевод термина и помнить его значение на протяжении всей статьи.

UB - является устоявшимся термином и его перевод на русский является скорее нежелательным

Преимущества Rust не ограничиваются безопасным доступом к памяти, есть ряд других полезных свойств, которые могли бы облегчить труд разработчиков ядра Linux. Взять хотя бы инструментарий для управления зависимостями. Много-ли тех, кому по душе сражаться с include путями в заголовочных файлах, раз за разом запускать pkg-config вручную, либо через макросы Autotools, полагаться на то, что пользователь установит нужные версии библиотек?

эээ… как говорится, где ядро linux, и где autotools?

Недостатки си достаточно очевидны. Как по мне, лучше будет доработать компилятор и добавить опцию, которая бы отлавливала такие моменты неопределённого поведения, чем внедрять дополнительный язык.
Лично для меня внедрение нового языка, тут же превратит элегантный код ядра в мурзилку.
Но вы же понимаете, что в результате «доработки компилятора» получится новый, совершенно другой язык программирования?

Clang делает тучу проверок, никак не прописанных в стандарте языка: например, кидает ворнинг на присваивание вида

if (a = b) /*...*/ ;

Предупреждение глушится парой дополнительных скобок:

if ((a = b)) /*...*/ ;

Мне не кажется, что из-за подобных проверок Clang перестаёт быть компилятором C.

К сожалению нет, потому что можно просто добавить дополнительную опцию компиляции, добавляющую этот функционал. И есть ряд компиляторов, которые намного строже следят за таким, запрещая неоднозначности (программировать с ними одно неудовольствие).

Но они никак не помогают при написании асинхронного кода

В Си надо читать мануал:

Смысл Rust как раз в том, что конечному разработчику не нужно читать мануал — благодаря типам, тебе компилятор просто не даст сделать что-то неправильное.
И при этом всё будет легко читаться.

Много думать нужно только в ситуации, когда ты сам собираешься написать свой асинхронный рантайм.

Ну а C++ в ядре нет и не будет.

В Расте есть точно такой же ансейф код, и уж точно он не является никакой волшебной кнопкой, которая сделает тебе всё хорошо, даже если ты не прочитал ман. RTFM всегда RTFM. В системном программировании не бывает серебряных пуль.

У меня складывается впечатление из комментариев под каждым постом про раст, что это какая-то секта и религия, настолько всё восторженно и однотипно.

Фишка в том, что в C мануалы надо читать всем, а в Rust - только тем, кто пишет unsafe. Так-то да, безусловно, вообще без них не бывает, вопрос лишь в количестве.

вы явно кривите душой. не читая мануалов я сейчас даже hello world на rust'е не напишу.

НЛО прилетело и опубликовало эту надпись здесь

хм, а зачем постоянно читать мануалы по си?

НЛО прилетело и опубликовало эту надпись здесь

вы явно преувеличиваете. если не брать библиотечные функции, то ub не так уж много, и у всех понятно откуда ноги растут, если воспринимать си как переносимый ассемблер, то они неожиданностью не являются.

НЛО прилетело и опубликовало эту надпись здесь
воспринимать си как переносимый ассемблер

Самый быстрый способ поймать UB. А некоторые чуть более продвинутые сишники этим еще и объясняют, почему в конкретном месте нет UB (конечно же чушь) и компилятор плохой (а вот тут согласен, ИМХО оптимизирующие компиляторы Си зло и мешают ему уйти на свалку истории отовсюду кроме эмбеда)
Самый быстрый способ поймать UB

можете проиллюстрировать?

Вот мой любимый.
И очень многие сишники, даже считающиеся опытными и компетентными, часто попадаются на том же, что если они пишут такой сишный код, они получат эдакий ассемблер, но это совсем не так в смысле абстрактной машины согласно стандарту, а значит и оптимизатора.

А почему вы не берёте библиотечные функции?

потому что в контексте написания ядра они неактуальны

В ядре Linux не переиспользуют чужой код? Я слышал обратное, но даже если это и так — пора это менять.

не понимаю как из «не используют библиотечные функции» вы вывели «не переиспользуют чужой код».


мы говорили о перечитывании стандарта языка си, в этом контексте «библиотечные функции» однозначно трактуются как C standard library, других в стандарте нет.
и да, эта libc из kernel space недоступна, надо обходиться без неё.

Ну да, тут надо перечитывать мануалы не по языку Си, а по внутреннему API ядра. Ничего принципиально не поменялось, только мануалы недоступнее стали.

Мануалы по Rust - естественно, нужны, как и с абсолютно любым другим языком (там, где они не нужны для написания кода, они становятся нужны, когда - не "если" - этот код ломается; JavaScript тому живым примером). Вопрос был изначально, насколько я понял, не об этом, а о том, чтобы знать детально все правила по безопасной работе с нижележащими компонентами, которые в C должны быть учтены на всех уровнях, а в Rust, если их учесть на нижнем уровне, выше они будут выражены в виде проверяемых компилятором ограничений.

Как ты собрался писать ядро ОС без Unsafe? Этот пост про линукс кернел.

Если не хочешь читать мануалы, пиши на интерпретируемых языках. Хотя рано или поздно и там придётся погружаться в подсахарные горы.

Ядро ОС без unsafe и правда не написать, но вот многие драйвера можно написать без unsafe без проблем.

Так это поэтому для Rust нет нормальных мануалов по структурам данных? Потому что они все требуют unsafe?

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Мне даже интересно стало -- а как, собственно, Раст (да и вообще любой язык программирования) может устранять проблемы в логике программы? Или помочь их устранить?

В статье примеры проблем перечислены. Большинство искусственные, конечно. Но когда это останавливало разработчиков новых прекрасных языков программирования? За Linux вот только страшновато. Обычно софт на Rust выходит корявым логикой своей работы, потому что Rust уж слишком ограничивает выразительные возможности.

Ограничивает выразительные возможности? Любопытно было бы взглянуть на пример того, как вы это понимаете.

Мой любимый пример - реализация двусвязного списка на Rust. Даже на Haskell это проще сделать.

Ну, допустим, вы его реализуете. А зачем? В какой практической задаче он будет значимо эффективнее обычного вектора?

… а даже если будет — есть готовый двусвязный список в виде std::collections::LinkedList

И чем это лучше реализации на Си? 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 продвинет тему безопасного кода, где первичен компилятор.

Тогда можно и правила дорожного движения (возня с borrow checker и типами) отменить: вроде бы большинство их соблюдает, но некоторые нет (unsafe), иногда неумышленно (тормоза отказали или ещё чего; баги компилятора). А если все будут думать головой (писать без ошибок) и смотреть по сторонам (делать все нужные проверки) — тогда и без правил (проверок компилятора) не будет аварий (крашей, порчи данных и т.д.).

вы неверно истолковали мой посыл. исключать "правила дорожного движения" нельзя. они должны подстраховывать, но не стать страховкой

при наличии этих правил, неумеющий ездить и полагающийся только на инструктора, не лучший участник движения.

Пусть лучше неумеющий ездить, но соблюдающий правила, чем опытный водила, который чихал на эти ваши светофоры, знаки и ограничения скорости.
Первый, может, медленнее и неуклюже, зато хоть точно доедет, а вот второй может приехать в могилу (иногда и не один).

Если бы все ездили только по правилам, аварийность была бы гораздо выше. Иногда приходится совершать запрещённые манёвры, чтобы избегать столкновений. В крупных городах приходится делать это довольно часто.

При движении на мотоцикле, так и вообще правила соблюдать небезопасно. Например, гораздо безопаснее двигаться в междурядье, а не по полосам движения, чтобы быть заметным в зеркалах заднего вида автомобилей.

Кроме того, аналогия плохая. Правила - для людей, а не для машин. Это как code style, а не как borrow checker. И правила довольно часто пересматривают, чтобы адаптироваться к новым реалиям. Про borrow checker такого не скажешь, адаптивностью он не отличается.

НЛО прилетело и опубликовало эту надпись здесь
НЛО прилетело и опубликовало эту надпись здесь

Все правильно написали. Замечу лишь, переход на раст с другого языка для повышения безопасности видится правильным решением. Вхождение через раст в программирование, расхолаживает и привьет плохой подход. Зачем думать о безопасности, подскажет ведь в случае чего.

НЛО прилетело и опубликовало эту надпись здесь

кто начал с раста, придя в питон, сломается. ведь теперь надо думать, чтоб не передать строку в функцию с числом

Я пришёл в Python после Haskell. Ничего не сломалось, в безумную обезьяну, которая пытается передать строки вместо чисел я не превратился. Что я делал не так?

Всё так. Язык со статической типизацией привил Вам навыки, которые в Python пришлось бы получать методом отладки падений на проде.

Кроме Rust есть множество безопасных языков программирования, которые позволяют работать со сложными структурами данных без необходимости пересекать границу unsafe. Тем, кому нужна безопасность, идут в эти языки, и пишут большую часть кода на них, оставляя только небольшие чувствительные к производительности участки для реализации на языках с более слабыми гарантиями безопасности. Но это небольшие участки кода, нет никакого смысла использовать для них такой громоздкий язык, как Rust, в котором они были бы, всё равно, реализованы unsafe.

Ядро ОС таким образом не напишешь. А если напишешь - то и на Rust точно так же получится: часть, которая раньше писалась бы на C, пишется в точно таком же стиле на unsafe Rust, всё остальное - #![forbid(unsafe)].

OS можно написать хоть на Lisp, хоть на JavaScript, хоть на Haskell. Примеров множество. Вы хотя бы гуглите, прежде чем ложные заявления делать.

НЛО прилетело и опубликовало эту надпись здесь

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

Так зачем при прочих равных мне выбирать более сложный язык программирования? Чтобы что?

НЛО прилетело и опубликовало эту надпись здесь
Ооо, наш любимый benchmarksgame, где «бенчмарк» = «оптимизированный изо всех сил (включая векторные инструкции) код под этот конкретный пример», и где при этом отсутствуют лютые ассемблерные версии. А сами исходники при этом мало сравнимы с кодом, который используется в «дикой природе» — чего только стоят предупреждения компилятора у исходников на C о непроверенных кодах возврата.
любой мало мальски нетривиальный алгоритм требует использования 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.
Интересно, а вы открывали binary-trees Rust #5? Судя по этому примеру, Rust не только позволяет безопасно (да, там нет unsafe) создавать структуры данных сложнее массива...

Справедливости ради, там используется bumpalo и rayon, в которых unsafe таки есть.

Ну… да? Но если так рассуждать, то в недрах любой программы, использующей std (даже Hello World), будет unsafe хотя бы для взаимодействия с ОС.
На практике unsafe используется даже в коде тестов, потому что без unsafe не триггернуть некоторые поведения.

А можно, пожалуйста, предъявить доказательства этому заявлению? А то звучит, как наглый пиз наглая намеренная ложь.

НЛО прилетело и опубликовало эту надпись здесь

Угу, unsafe там — из-за from_raw_fd, который в принципе не может быть безопасным, поскольку файловый дескриптор фактически просто число, и нет гарантии, что некое наперёд заданное число действительно отвечает какому-то файлу. Вызывать же её приходится из-за того, что openpty из крейта nix — тонкой обёртки над API unix-like операционных систем — возвращает пару файловых дескрипторов.


Короче, не убедили.

он просто не позволяет реализовывать некоторые алгоритмы в safe-режиме
Сильное заявление. Мне даже интересно, почему (на ваш взгляд):
  1. эти некоторые алгоритмы не являются вычислимыми
  2. 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 linked list» и ткнуть по второй ссылке (при том что первая — документация std::collections::LinkedList).
Вот, держите: ссылка на полный код. Там есть тесты, которые успешно выполняются.

Да что же любители 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()
    }
}
НЛО прилетело и опубликовало эту надпись здесь
Когда для rust появится хотябы вторая реализация компилятора?
Я попробую чуть более подробно развернуть каждый пункт.
Как минимум, топик написан 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.



Проблема в замещении системных языков — готовые компоненты очень сильно полагаются на другие готовые компоненты. Переписывать имеющийся код (хоть ядро Linux, хоть условный nginx) просто так никто не будет, а если вы уже имеете проект на C (и особенно штат разработчиков на С) — переход на Rust не будет сверхдешёвым, даже если писать на нём только какие-то новые модули: тут сплошной unsafe из-за FFI («а зачем нам безопасный Rust если у нас везде unsafe»), там третьи сутки борются с borrow checker'ом потому что пытаются писать на Rust так же, как привыкли на C («компилятор писать код мешает»). Получается, что на новом языке выгодно писать только что-то совсем новое, а множество таких проектов не очень уж часто пересекается с системным программированием. Хотя есть, конечно, и исключения — например Fuchsia активно использует Rust.
Насчёт 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 системный не в том же самом смысле, в каком системный Си.
Go предназначен для написания больших распределённых по сети систем, типа Kubernetes или просто каких-то сервисов.
А Си предназначен больше для работы с каким-нибудь лоу-левелом, как при разработке операционных систем или embedded
НЛО прилетело и опубликовало эту надпись здесь

Я довольно хорошо осведомлён о том, что чувствует коммьюнити в целом по отношению к системным языкам, и у меня сложилось впечатление, что все хором сильно топят за Зиг, а вот с Растом ситуация очень divisive -- половина его ненавидит, половина превозносит.

НЛО прилетело и опубликовало эту надпись здесь

OSи пишут на разных языках: Lisp, Java, Haskell, Forth, ML и даже JavaScript. Написать небольшую OS для конкретной железяки - не такой уж и амбициозный проект. У меня второкурсники микроядра с вытесняющей многозадачностью писали за месяц. Человечество уже давно знает, как это делается. В этом плане Rust ничего принципиально нового не предлагает...

Ну, разве только то, что не получится привычные структуры данных использовать для всяких очередей таймеров или планировщиков пакетов. В этом есть некое интеллектуальное приключение. Но что-то я сомневаюсь, что оно упрощает написание OS, а не усложняет. В той же Redox довольно печально с этим дела обстоят: вместо кучи таймеров активное ожидание с переключением контекстов, очередями событий служат deque и т.д. Не самые эффективные решения, мягко говоря, особенно для систем реального времени.

Redox по-моему всё, умер.

Типа, не смогли сделать Redox, поэтому пришли в Linux? Опасные ребята...

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, но и его пилили-пилили, да так и не допилили.

О Расте складывается ощущение, что он слишком широко взял, и из-за этого несколько переусложнился. В таком виде на замену C он не очень подходит. На нем было бы удобно писать Linux что-то такое монументально и очень сложное, типа ОС. Но ОС-ы в своей массе уже написаны и с нуля переписываться будут вряд ли.

Так как раз ОСы на нём писать крайне неудобно. В этом-то весь цимес. Он слишком ограничивает.

Тогда остаются высоконагруженные системы реального времени, где цена ошибки очень велика. Но сколько таких заказчиков? Точнее сколько таких типов заказов (ведь один раз написал — продавай везде). Вот интересно как раз в этой сфере продвижение Rust посмотреть.
Ну например вот, особенно
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) народная мудрость.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий