Pull to refresh

Comments 230

Писать огромное количество кода только ради того, чтобы смочь сложить два и два без лишнего рантайма — это, конечно, прикольно.

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

Автору респект за "вызов" было интересно читать.

В двоичных кодах два на два умножить не так уж много текста надо

Операционная система не пустит к процессору с минимальным текстом. На микроконтроллере да, 2-3 байта и весь код.

Не понял почему человека замунусовали?

Он немного кричаще выразился - но суть-то что соблюсти OS API по вызову нового процесса (формат elf или exe или чего ещё) и это не 4 байта в итоге - верна.

Кому-то все равно пришлось этот код написать. core ведь откуда-то знает как складывать числа.

терминально бесполезный мусор.

мне же приходится бороться с мусорной пропагандой

на это ловятся все бездарные тупорылые дошколята, которые нажрались пропаганды и пошли блеять. Т.е. ЦА раста является дошколятский биомусор, который код писать не может

почему ЦА говнораста - это веб-обезьяны и бездарные докшоялта? Почему всё, что пишется - это всякая дристня, которую пишут на жс/дристоне/другой скриптухе?

ещё раз. Какой может быть с тобою "по делу", если ты жертва пропаганды? Ты не можешь существовать вне

в любом случае молодец

Зная вышеперечисленные факты (и многие другие), сложно воспринимать сравнение так называемого языка программирования Rust с чем-то нормальным всеръёз. Для более подробного и глубокого обсуждения рекомендую присоедениться к чату: https://t.me/proriv_zaparti2

Удивляет, что у некоторых людей присутствует иррациональная ненависть к Расту. Я так понимаю, в основном это сишники и плюсеры. Казалось бы, не нравится - проходи мимо. Аналогичное явление я наблюдал у линуксоидов, НЕНАВИДЯЩИХ виндоуз.

UFO just landed and posted this here

Я бы хотел, чтобы в МГУ (самом МГУ!) ученые и студенты были открыты к познанию. Ведь в этом и есть суть университетов, нет? Слишком многого хочу?..

Не слишком, но давайте будем честными: ВУЗ, где преподаватели знают про Rust и даже могут подискутировать о нем, уже довольно хорош по сравнению со средним по больнице. В моем университете меня ругали за лишнюю переменную (память тратится типа) в коде. Или что процессоров по технологии ~32нм не может существовать в природе, потому что это меньше длина волны видимого света. Никто не запрещает подвергать сомнению слова преподавателя, перепроверять информацию, затем возвращаться к нему для обсуждения. В сомнении рождается истина (с)

на ютубе есть лекция Жореса Алферова из которой можно узнать что он сам не знает что такое маркетинговые нанометры, он уверен что это размер транзистора.

Лично я около трех раз ловил на экзамене преподов что они сами не понимают что-то по мелочам. К моему счастью они признавали ошибку. Но это нормально.

Ну вообще "эффективная плотность упаковки 'неквадратных' элементов" - это как раз самая лучшая метрика, для такого понятия, как размер элемента.

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

Ну он в каком-то смысле прав, для планарных транзисторов меньше условных 24-28нм сделать нельзя. Но вот когда оно в тридэ, то можно сделать из этого 14нм, там же 2 транзистора на ячейку!

Репетиторствовал как-то студенту по плюсам, и сделали с ним лабку несложную с использованием векторов. Так на него наехали — дескать, оверхед, "из пушки по воробъям" (прямая цитата), нужно было сишный указатель со сдвигом.

Без деталей не ясно, насколько использование вектора - оверхед.

Может, там нужен был один элемент, а передавался вектор и индекс.

Или это курс по хайлоад, и накладные расходы на работу с вектором имеют значение.

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


Ну и вспоминается одна из историй Страуструпа, где ему говорят "вектор фигня, в указателей расходы меньше", а он уточняет про уровень оптимизации, и тот оказывается -О0. Вот серьёзно, "оптимизировать" вектора в указатели — это последнее дело, только если все остальные методы уже опробованы.

Отличие явное. Си без стандартной библиотеки остается языком Си (то что происходит в ядре Линукса/UNIX которые собираются без всех зависимостей, в том числе и без стандартной библиотеки), а что останется от Раста без стандартной библиотеки? Будет ли это Растом?

Ну и полное унижение для большинства программистов - а можете ли вы оперировать микросекундами на своём любимом языке? - это можно на ассемблерах и Си. В прочих языках всё недертминированное во времени придется вырезать и от любого языка останется нечто Си-подобное.
Только не надо передергивать, я не говорю что Си это хорошо всегда и для всего.

а что останется от Раста без стандартной библиотеки? Будет ли это Растом?

Да, будет. Автор статьи отломал только импорты. Сам язык от этого не перестал быть языком. Можно все так же использовать высокоуровневые абстракции, чем активно пользуются разработчики.

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

Но они видимо Столярова не посещали и не знают, что это невозможно.

Вообще, кому интересно рекомендую книгу Rust Embedded.

вмк всегда очень не равный состав преподавателей имел, люди которые пришли из промышленности (в те далекие времена, когда приходилось там бывать - Королев и др) это top notch, насколько знаю сильные люди там еще есть, но мало, и не Столяров, хотя против его книг ничего не имею, откровенного вранья там не замечал, просто по серьезному он не программист, а преподаватель скорее, хотя возможно сам думает иначе, так что все что он про rust пишет лучше не читать (imho как обычно)

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

Хм...проверим статистику что у нас там по RTOS, драйверам и их поддержке:

MOST POPULAR RTOS (2021)

  • Deos (DDC-I)

  • embOS (SEGGER)

  • FreeRTOS (Amazon)

  • Integrity (Green Hills Software)

  • Keil RTX (ARM)

  • LynxOS (Lynx Software Technologies)

  • MQX (Philips NXP / Freescale)

  • Nucleus (Mentor Graphics)

  • Neutrino (BlackBerry)

  • PikeOS (Sysgo)

  • SafeRTOS (Wittenstein)

  • ThreadX (Microsoft Express Logic)

  • µC/OS (Micrium)

  • VxWorks (Wind River)

  • Zephyr (Linux Foundation


Ой, какая неожиданность - все они написаны на С/С++ (в большей степени на С). А как же так то...не надежно все это - сколько безногих разработчиков и промышленных систем.

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

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

UFO just landed and posted this here

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

Вот только бизнесу абсолютно начхать на чем вы там будете реализовывать задачу - его волнуют сроки, суммы и доступный уровень надежности при первых двух параметрах. И эмбеддер с опытом решения промышленных задач всегда отдаст предпочтение готовым либам, прошедшим через 100 тысяч узкоспециализированных разработчиков и экземплам по RTOS от разработчиков систем, а выигранное время потратит на бизнес-логику процесса. А не писать с нуля драйвера для интерфейсов, клиентов, серверов и прочего)

Вы будете таки смеяться, но бизнес очень даже понимает преимущества, которые дает раст при разработке и особенно при поддержке систем. Я говорю не про титанов из FAANG которые уже давно в теме, а про железячников: ядра операционных систем, системы реального времени, авионика, automotive сектор и в скором времени космос. Ferrous systems не зря пилят расширенную формальную спецификацию языка именно для критических систем.

Чтобы понять почему, достаточно ответить на вопрос, почему Торвальдс не показал свой знаменитый средний палец Расту так как делал это C++ все 30 лет.

Используя вашу логику можно сказать что и C++ никому не уперся, ибо серьезный бизнес уже 50 лет как использует COBOL. Но это уже, простите, демагогия.

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

На подобии того, как в "низкоуровневое" языке появились СОМ интерфейсы, которые вообще-то крестовые Шарп пародии на самих себя. Как это воспринимать нормально?

Вы точно отличаете язык C++ от поделия MS?

Никакого COM в C++ нет и не было

Если ты хочешь кодить на Винду, ты обязан это знать. Почти все системы ОС на СОМ перешли. Как пример, винда может давать тебе доступ к геоданным, но надо знать СОМ что бы ими пользоваться. В этом мысль

Да нет, не обязан. На работе довольно большой проект под 3 платформы, но ни намёка на COM там нет.

К тому же, моё утверждение всё ещё в силе - COM не часть языка С++, а часть API для одной ОС, которая местами склонна к overengineering. С тем же успехом можно сказать, что в языке С есть ООП просто потому, что часть интерфейсов Linux требуют чего-то подобного.

Ну ты то можешь и не использовать СОМ, но ты теряешь тонну функционала и кроссплатформенная разработка превращается в костыли в которой каждая платформа имеет кучу конфигов чего она может и не может. Ну или просто ударится в минимализм, забив на все "фичи" которые потенциально можно реализовать у всех.

Ок

Для Rust есть RTIC для Cortex-M. Довольно таки интересный аналог имеющихся RTOS.

Я хочу отметить, что с точки зрения "zero runtime", как его понимают студент и доцент, C++ попадает в одну кучу с Rust, особенно если не выключать exceptions.

Ой, какая неожиданность - все они написаны на С/С++ (в большей степени на С). А как же так то...не надежно все это - сколько безногих разработчиков и промышленных систем.

RFC стабилизирующее no_std в Rust датируется 2015-м годом. Давайте посмотрим когда же были выпущены в продакшн вышеперечисленные RTOS:

Deos is a time and space partitioned real-time operating system (RTOS) that was first certified to DO-178B level A in 1998

Хм, 17 лет...

embOS — The preferred RTOS for embedded systems since 1992

23 года...

FreeRTOS: Initial release: 2003

О, всего 12 лет!

И т.д. и т.п. Прям странно что все это RTOS, вышедшие за десятилетия до того как Rust выпустил 1.0 версию (и стабилизировал no_std/no_core функционал) были написаны на C/++ а не Rust. Наверное вы правы, это вина Rust что разработчики решили писать эти системы на C, а не на языке который не будет создан несколько десятилетий спустя...

UFO just landed and posted this here
Иными словами, существует удовлетворяющая стандарту реализация, которая не скомпилирует ядро линукса

Есть, называется clang :^)

При этом поддерживает далеко не все платформы, на которых собирается Linux, и для поддержки сборки которой потребовалось вносить патчи как в само ядро, так и в clang, для поддержки GNU-расширений.

А какие не поддерживаются для которых есть бэкенд?

Написано по ровно той ссылке, которую вы и привели (._. )

Не увидел, там я вижу лишь список поддерживаемых платформ, и они все есть в бэкенде llvm. Соответственно мой вопрос: какие есть платформы из линукса, поддерживаемые бэкендом llvm, но которых нет в этом списке.

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

Только не надо передергивать, я не говорю что Си это хорошо всегда и для всего.

Си - это хорошо всегда и для всего!

Если пишешь ты на Си,

Будь хоть трижды ламер -

Каждый скажет о тебе:

"Он крутой программер!"

Именно это свойство — zero runtime — делает Си единственным и
безальтернативным кандидатом на роль языка для реализации ядер
операционных систем и прошивок для микроконтроллеров.

Очень мило. Особенно на фоне того, что буквально на днях у Лины заработал Linux драйвер графики для Apple M1, написанный на расте, а в ядро Linux вот-вот заедет его поддержка, одобренная самим Торвальдсом.

Комментарии Лины по поводу разработки

On the Rust side, I have to say I'm super pleased with my experience writing a driver like this in Rust! I've had zero concurrency issues (and the driver uses fine-grained locking, there's no big driver lock) - once single processes worked, running multiple apps concurrently just worked. Also zero memory leaks, dangling CPU or GPU pointers, use-after frees / free order mistakes, or anything like that! The only memory corruption issues I ran into were either fundamental mistakes in my unsafe DRM abstraction or core GPU memory management code, or happened from the GPU side (there's an issue with TLB invalidation, that's what the ugly workaround is for).

I feel like Rust encourages good driver design and then the compiler goes a long way towards making the resulting code correct. All in all I didn't really have that many bugs to fix, mostly just logic issues (both because I'm new to DRM and because the GPU interface is all reverse engineered and we're still working out the details).

The workaround for the GPU-side TLB inval issue has a large performance hit, but without that, kmscube does run at 1000+ FPS, and that's with a lot of suboptimal components that will be improved over time (e.g. my current allocator allocates/maps/unmaps/frees tons of little GPU structures per frame), so I'm also very optimistic about the performance aspect!

The only major Rust issue I ran into is the lack of placement new, which I ended up working around with a very ugly place!() macro (it still has a soundness issue too, I need to fix it to drop things if initialization fails halfway through). Without that, I was quickly overflowing the kernel stacks (which is particularly ugly to debug without CONFIG VMAP STACK, which I didn't have set at first...). With the macro though, the stack frames are under control enough that there's no issue, but l'd really love to see core language support for this. I think it's really necessary for kernel/embedded development.

Про эмбеддед я вообще молчу

lack of placement new

Ох, извечная боль...

Меня терзают смутные сомнения. Мне почему-то кажется, что вы писали не на расте, а на ассемблере, который компилируется растовским компилятором. Но если так, то почему вы это сравниваете с greet3.c из главы "Нулевой рантайм в Си" который написан исключительно на си, без каких-либо ассембленых вставок и миллионов указивок си перестать работать как си?

"Нулевой рантайм в Си", написанный на Си, не работает. Чтобы он заработал, ему еще нужно 2 файла, которые не компилируются компилятором Си. Можете и на Расте функции, реализованные целиком в ассемблере, вытащить в отдельные файлы, либо на Си затащить их в файл Си (что и было сделано в конце).


миллионов указивок си перестать работать как си?

Если вы про атрибуты, то это нормальный код на Расте. Ничего не "перестает работать как раст", borrow checker не отключите, не надейтесь :)

Можете и на Расте функции, реализованные целиком в ассемблере, вытащить в отдельные файлы

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

либо на Си затащить их в файл Си (что и было сделано в конце).

Этот подход мне и не понравился. Там нет си вообще, там какая-то уродливая и нечитаемая фигня, зачем назвали это си? Сравните с изначальным вариантом, когда вынесли отдельно чистый ассемблер и отдельно - чистый и всем понятный си.

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

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

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

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

Адепт секты истинных программистов
Единственным прибежищем программистов-любителей внезапно оказалась веб-разработка. К сожалению, начав в этой области, люди обычно ею же и заканчивают. Разницу между скриптами, составляющими веб-сайты, и серьёзными программами можно сравнить, пожалуй, с различием между мопедом и карьерным самосвалом; кроме того, привыкнув к «всепрощающему» стилю скриптовых языков типа того же PHP, большинство неофитов оказывается принципиально неспособно перейти к программированию на строгих языках типа Джавы или тем более Си, а хитросплетения Си++ для таких людей оказываются за горизонтом понимания. Веб-кодеры, как правило, получают неплохие деньги, не подозревая при этом, что такое настоящее программирование и что они для себя потеряли.
© А.В. Столяров, Программирование: введение в профессию Стр. 15.


и борцун с международными террористами
За несколько лет, прошедших с момента предыдущего издания, мир несколько изменился: группа международных террористов, по недоразумению называющихся комитетом по стандартизации Си++, развернула весьма бурную и эффективную деятельность по окончательному уничтожению языка. Вышедшие последовательно «стандарты» С++11, С++14 и, наконец, С++17 не переставали удивлять публику: каждый раз казалось, что более мрачного и безумного извращения придумать уже нельзя, и каждый раз выход очередного «стандарта» наглядно демонстрировал, что всё возможно. Если под «языком Си++» понимать С++17, то о применении такого инструмента на практике не может быть никакой речи, т.е. с языком Си++ следует попращаться, устроить торжественные похороны и поискать альтернативу; впрочем, то же самое можно сказать про все его «стандарты», начиная с самого первого, принятого в 1998 году; строго говоря, язык Си++ как уникальное явление был уничтожен именно тогда.
© А.В. Столяров, «Введение в язык СИ++», стр. 7
UFO just landed and posted this here

А он больше не преподает с 21 года, так как отказался делать прививку

Это не Царь. Царь анонимен, а Столяров — нет и до прямых оскорблений оппонентов вроде не опускается.

UFO just landed and posted this here

единственный способ написать быстрый программный комплекс — писать все на ассемблере

Это Ваш пересказ слов чувака. Смысл такого утверждения туманен. Что такое "быстрый"? В сравнении с чем? Быстрота нужна для чего? И что такое загадочный "программный комплекс"? Я могу представить себе задачи, когда нужно считать каждую микросекунду (для чего нужен сторонний счётчик, кстати) и контролировать каждый поток буквально по тактам. В этом случае ассемблер - самый простой выбор для человека, которому нужен результат, а не понты и имитация понимания.

Громкое имя, а на деле — пшик

Подобное огульное утверждение вряд ли имеет смысл. Каждый "пшик" имеет имя и фамилию.

UFO just landed and posted this here
>когда нужно считать каждую микросекунду
Я тоже могу представить себе задачи, когда речь идет о сотнях терабайтов данных в сутки, например. И никто микросекунды не считает, потому что цель программного комплекса, например, подготовить отчет для регулятора сегодня «к закрытию банковского дня». И это тоже программный комплекс, и тоже быстрый — но в своем понимании. И даже мысли писать что-то на C++ никому в голову не приходит, прошу заметить, не говоря уже про ассемблер.

>Смысл такого утверждения туманен.
Вот именно по этой причине. Чувак, который делает такие утверждения без уточнения, что такое быстрый и так далее — балабол. Я не согласен с вашим выводом про ассемблер, несколько по другой причине, нежели озвучил 0xd34df00d, а скорее по той, что очень редко требования по быстродействию относятся ко всей большой системе, И даже если вы пишете что-то на ассемблере, уже очень давно имеет смысл писать только самые критичные части, и только в тех случаях, когда ваш компилятор не умеет скажем использовать все возможности процессора. Все же остальное зачастую можно написать на том, на чем быстрее и дешевле. Потому что «нужен результат» как правило почему-то не когда попало, а вчера.

для опровержения этих пунктов мне придется писать максимально уродские хэлло ворлды, которые только можно представить

Погодите, и вы вправду не считаете что в этой фразе что-то нет так?

Этот пост — письменное изложение вот этого доклада с C++ Russia?

Возможно то, что обоих авторов зовут Роман не просто совпадение.

Я вроде как понимаю содержание этого замечательного цикла статей, но определённо и полностью не понимаю смысл.

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

Отсюда вопрос: а что, обнаружилось что в некоторых кругах организована травля Rust? Если да, то чем она может быть вызвана и есть ли координация с Гугол ринувшимся делать Carbon чисто случайно как только Rust начал набирать популярность?

UFO just landed and posted this here

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

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

Потому, что первый фильтр происходит по формальным критериям (в том числе корректности написанных утверждений: есть методика испытаний, есть 0.99999% производительности - так и пиши) и при их невыполнении девочка-секретарка (в лучшем случае аспиратнтка) напишет "не пущать".

А второй фильтр, состоящий из содержательных, тот самый "нетривиальный код написанный естественным образом" - фиг докажешь и представишь как плюс.

> Почему наши российские учебники (книги этим тоже грешат, но меньше) по IT такие плохие

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

ps

нетрудно привести примеры хороших оригинальных книг по программированию написанных по собственным работам, начиная с kernighan & ritchie, интересно спросить того кто карму минусовал за это сообщение -

Вы можете привести контрпример, типа хорошей книги по программированию написанной по чужим работам (компиляции) кроме учебников конечно?

UFO just landed and posted this here

согласен, хорошо написано, и не компиляция конечно, Pierce phd делал в Carnegie Mellon, одна из лучших школ по CS, supercomputing center тоже там, кстати там тоже Gordon Bell работал (digital vp r&d, т.е. прямое отношение к созданию VAX), это к тому что в случае TAPL человек прямо в центре событий находился и сам активно работал, его thesis (Programming with Intersection Typesand Bounded Polymorphism) стоит взглянуть как пример хорошей теоретической работы, в моем понимании TAPL типа осмысление достигнутого в части языков, но в общем Вы правы

ps

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

UFO just landed and posted this here

Интереснейшая цитата возбудила моего внутреннего конспиролога того больше.

Как Dart попал в and many more, это же предел мечтаний и свет (Истины) в окошке?

Разве changes in the idiomatic design не должны попадать в категорию goals вместо barriers?

Насколько я понимаю, получив отказ на просьбы пустить проприетарщину в ядро, Гугол теперь строит интерфейсы между собой и ядром Линукс, что должно дать Андроиду ядро посвежее и обновлений поболе и подешевле. Если бы Rust этому не способствовал, Гугол его в ядро не продвигал бы.

«Наверно Rust есть хорошо и Гугол хочет его для себя» - подумал внутренний конспиролог.

есть ли координация с Гугол ринувшимся делать Carbon чисто случайно как только Rust начал набирать популярность?

В FAQ Carbon прямым текстом написано "If you can use Rust, ignore Carbon".

У Гугла огромная, гигантская, размером с небо и луну база кода на C++, с которой надо взаимодействовать и которую надо поддерживать. В Rust довольно неплохой interop с C/C++, но не без заковырок. Facebook потянул втащить Rust в свои инструменты и интегрировать с наиболее важными внутренними библиотеками, а Google решил что слишком рисковано, и придумал язык, у которого interop совсем тривиальный и "точно" ничего не поломает.

Это штука с очень ограниченной аудиторией: те, кому надо интегрироваться с огромным количеством старого C++ с минимальными усилиями, но новый код хочется писать на чём-то более безопасном.

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

А статью точно студент писал?
Начал читать и в какой-то момент прям пахнуло нафталином из плохой методички по 30 лет никому не нужному предмету (назидательный тон и оторванные от реальности лет на 20 выкладки):

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

Дедушек не надо обижать то уж.. Они не все еще нафталином пропахли :-)

Так это, чукча не читатель, чукча писатель..

Вы как будто в универе не учились. Сказано - пояснительная записка на 15 страниц, а у тебя только 8. Что делать? Обмазывать канцеляритом в 6 слоев, разумеется.

О, студент-автор статьи прикольно врёт:

let xs = vec!["lorem", "ipsum", "dolor"];

xs.iter().filter(|item| item.ends_with('m')).nth(0)

Да, исходный код стал значительно меньше, вот только получаемый машинный код на порядки вырос, да ещё и стал существенно медленней. Предлагаемая тут сущность, передаваемая в filter, и вовсе является замыканием из мира функционального программирования и представляется в машине весьма нетривиально; желающим предлагается посмотреть получаемый машинный код.

Одна маленькая проблема, он забыл включить флаг оптимизации. Вот дизассемблированный код c "-C opt-level=2". "Желающим предлагается посмотреть" на 2 с половиной ассемблерные инструкции, в которые превратился вызов filter, а также почитать что такое zero cost abstractions в Rust...

Самый залайканный первый комментарий на реддите раста к постам типа "код на расте медленнее, чем код на языке X" - "а вы в релиз режиме код собирали?"

Это синтетика, всё-таки — там всего три элемента, с которыми llvm делает истинные чудеса. Я даже не сильно удивлюсь, если в очередной редакции он подставит "lorem" вместо этого кода, сделав полное вычисление.

Но, конечно, странно писать фильтр и брать первый элемент в энергичном языке. То есть, код

head $ filter ( ((==) 'm') . last ) ["lorem", "ipsum", "dolor"]

выглядит разумно. Но уже в Ocaml я бы использовал List.find:

List.find (String.ends_with suffix:"m") ["lorem"; "ipsum"; "dolor"]

Иначе для длинных списков работа далека от оптимальной.

Ничего странного: язык-то, может быть, и энергичный — а вот итераторы "ленивые".

Обычно за ленивость приходится платить... Не в этом случае, но.

Меня удивило, что при включении оптимизаций он не сократил весь main до одного ret — тут ни о каком lorem речи не идёт, main же ничего не возвращает, и не имеет никаких побочных эффектов, кроме выделения памяти. Именно так компилятор делает, если заменить vec! на &. Но почему‐то не если убрать vec! полностью (т.е. заменить тип xs с Vec<&'static str> на [&'static str; 3], или на &[&'static str; 3] в первом случае).

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

Думаю дело в том, что когда создаётся локальная переменная типа [] или Vec, а не &[], компилятор должен создать и инициализировать её на стеке (в куче, для Vec), и догадаться что создавать её не надо он может только если к ней применяются константные методы (коим ends_with не является).

Я заменил метод на константный и у меня вариант с Vec скомпилировался в один ret:

(Дисклеймер: Максимально уродский хак, требующий unsafe nightly rust)

#![feature(const_slice_index)]
pub const fn ends_with_m(s: &str) -> bool {
    unsafe {
        return *s.as_bytes().get_unchecked(s.len() - 1) == 'm' as u8;
    }
}

pub fn main() {
    let xs = vec!["lorem", "ipsum", "dolor"];
    xs.iter().filter(|s| ends_with_m(s)).nth(0);
}
UFO just landed and posted this here

"Оптимизации хрупки, мой друг!"

Реально, я видел подобное же на C++ с векторами и самописным zip'ом с лямбдами. Код совершенно неидеоматический, но компилятор "урезал осетра" до неотличимости от идеоматического кода. Но вот шаг влево, шаг вправо привёл к тому, что компилятор оптимизировать не смог, и получились несколько страниц ассемблера.

Но, конечно, странно писать фильтр и брать первый элемент в энергичном языке.

Просто кривой код. То, что нужно автору, называется find:

let xs = vec!["lorem", "ipsum", "dolor"];
xs.iter().find(|item| item.ends_with('m'));

Емнип, это принципиальная позиция у них там, не врубать оптимизации, <sarcasm>ведь настоящий программист и без них может написать все идеально оптимально, а сложный компилятор такому программисту только мешает</sarcasm>

Падажжите. Где опровержение изначальной цитаты в статье?

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

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

Это я конечно утрирую. Но я был бы осторожен с теми, кто говорит "Долой С, перепишем все на Раст и заживем". Впрочем тех кто хочет все переписать на С я бы тоже обходил стороной. :)

Её и опровергать нечего, это же очевидная неправда.


Дело скорее в том, что компилятор раста сам решает, когда владение "должно" (с его, компилятора, точки зрения) перейти от одного игрока к другому. А решать это вообще-то должен программист, а не компилятор.

При передаче по значению происходит передача владения, если передать ссылку или клонировать объект — передачи владения не происходит. Писать или не писать & там, .clone() или вовсе поставить трейт Copy решает не компилятор, а программист. Всё.

И эти вещи сто лет как называются "make compiler happy" в комментариях в коде, даже на Си. То есть если посмотреть с более высокого уровня, цитата таки права — программист вынужден подстраиваться под компилятор.

И эти вещи сто лет как называются "make compiler happy" в комментариях в коде, даже на Си.

В 99% таких случаев компилятор всячески пытался предостеречь программиста от ошибки. Просто программист этого не понимал.

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

Эти вещи определены однозначно, как раз таки в отличие от компилятора C++, который, например, может делать copy elision или «продление времени жизни», а может и нет, по желанию левой пятки.

Вот как раз в C++, продление времени жизни является адским хаком, не вытекающим напрямую из семантики, про который, по видимости говорят Столяров и К°, транзитивно перенося его на Раст.

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

Я это проходил, когда начинал писать на Haskell. Очень больно было, прям до слёз. Но потом стало гораздо легче даже в C++.

Изменить дизаин и выкинуть стильные-модные-молодежные штуки. Все так.

Если вы считаете себя более умным и опытным человеком, чем все эти люди, придумывавшие математическую теорию, на её основе систему типов, потом поддержку в компиляторе и т.д., и считаете что они работали зря - то выкидывайте, конечно.

Просто интересно, с ASAN, UBSAN и т.д. вплоть до -Wall вы так же поступаете? Новомодные же игрушки, тоже код писать мешают.

я не умнее и опытнее чем люди которые создали теорию, и на основе нее компилятор Раста. но я умнее чем сам компилятор Раста.

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

да вы и сами пишете "более чем в половине случаев" - значит в остальной "почти половине" вы танцуете просто по прихоти компилятора

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

ps: языки с динамическими типами в этой аналогии это одноколесный мопед с ракетным движком, при достаточном старании тоже можно не въехать в стену, и можно по рампе перепрыгивать перекрёстки, но зачем?

но я умнее чем сам компилятор Раста.

Ой ли?


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

А почему вы сомневаетесь, что человек может быть умнее чем программа?

Тем более незнакомый вам человек, видимо вы по-умолчанию считаете всех недоумками.

Компилятор, в ваших глазах, наверняка умнее меня, а вы, раз можете мне разьяснить его логику, умнее и его и меня. Не много на себя берете?

Компилятор не божественен, он может доказать безопасность для ограниченого сабсета всех возможных корректных програм, просто есть надежда, ставка на то, что этот сабсет достаточно широк для достаточного удобства программирования. (Референс можно нагуглить по "Rust's radical wager".)

Тот факт, что практически возможно написать абсолютно безопасный код, который Раст не примет, может удивить разве-что оголтелого фанбоя.

И, по сути вопроса. Момент который конкретно мне дал интуицию, что придется прогибаться под компилятор зря, был, если я правильно помню, таков: мне надо было разделить массив на две части (скажем, [0..1] и [1..6]) и менять значения в одной, сверяясь с содержимым второй. На что Раст жаловался что я "дважды беру одно и то-же", и я могу его понять. Но на практике, эти части не пересекаются, и я это знаю, и в моей программе, соответственно, это не могло вызвать проблем. А компилятор нет. Вас может убедить что проблем не могло-бы быть, потому-что есть API языка который это разбиение поддерживает (только "ночной экспериментальный").

Советы от умных людей (вас может шокировать, что я советовался с умными людьми до вас) заключались в том, что нужно:

  1. либо менять поведение программы, не брать слайсы, а передавать индексы (это "делать долгий крюк хотя есть короткий поворот не по рельсам"),

  2. либо использовать unsafe, (понятно почему это не ответ)

  3. либо использовать "nightly-only experimental API". https://doc.rust-lang.org/std/primitive.slice.html#method.split_array_mut (тоже должно быть понятно, что "просто используй экспериментальный API" - не серьезный подход - никто даже не гарантирует что он продолжит существовать)

Там вообще-то стабильное api тоже есть, можно бы и его использовать было

Либо мне нужно было именно второе из них, либо split_at_mut тогда тоже было экспериментальным. Думаю, сути моего возражения это не меняет.

Практически, нужное мне поведение, стало "признано безопасным разработчиками Раст" и имплементировано средствами языка (через unsafe, неудивительно). Просто контрпример тому, что "компилятор лучше понимает".

UFO just landed and posted this here

Разным людям интересно разное, например, мой камент был ответом на:

"-но я умнее чем сам компилятор Раста. -Ой ли?"

И в этом контесте, уточнения про внимательность и легкость это shifting goalposts and strawmanning.

И, по сути нового вопроса, да. Компайлер точно внимательней, но если false positive rate - 50% (к счастью, это не про Раст), то практического проку мало.

насколько легко написать код, который раст примет?

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

Не совсем понимаю какие вы пытаетесь из этого делать выводы.

UFO just landed and posted this here

да вы и сами пишете "более чем в половине случаев" - значит в остальной
"почти половине" вы танцуете просто по прихоти компилятора

А если code review находит проблемы только в половине случаев - значит в оставшейся половине это нагрев воздуха впустую? Или подтверждение того, что в программе нет странных ошибок, тоже чего-то стоит?

Я готов допустить, что вы умнее компилятора. Но уверен, что он внимательнее, не устаёт и не отмахивается "да фигня, очевидно это сработает". Для меня это достаточная причина, чтобы помочь компилятору проверить мой код, даже если это требует некоторых дополнительных усилий.

Супер, я согласен, что это лишь вопрос того, окупаются-ли затраченые усилия.

Аналогия с код-ревью, это если на каждом ревью половина правок/коментов неоправданые, просто false-positive предрассудков ревьюера, обсудить с ревьюером смысл нельзя, и ваш деливери блокируется из-за них.

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

Почти так, только это не предрассудки, а нарушение style guide. И поначалу в новой компании у меня десятки комментариев что это не так и то не этак, а потом втягиваешься и они пропадают.

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

А требовать, чтобы как в анекдоте, настоящему программисту везде позволяли писать как на Фортране - нет, спасибо. Я люблю строгие инструменты с ремнями и плётками, чтобы заставляли делать хорошо, а не просто "у меня работает". Ловить баг даже на дев-стенде гораздо муторнее, чем получить десяток раз линейкой по рукам при сборке.

Я в целом со всем согласен, и в плане строгих инструментов тоже. Нужен только правильный баланс cost/benefit, а он у каждого проекта разный.

Моя претензия в том, что "язык умный, а ты тупой" это нездоровый, да и фактически неверный подход. Но, думаю, этот вопрос мы разобрали.

И, чтобы передать ещё моей интуиции по этому поводу: servo, постер-бой Раста, написаный, если не ошибаюсь, самими создателями языка, содержит в себе больше сотни упоминаний #[allow(unsafe_code)] (включая достаточно забавное "This code is highly unsafe.")

Что говорит нам о том, что создатели Раста знают (или считают что знают), где он компетентен (почти везде), а где нет, и нужно взять в свои руки контроль. За что им большое уважение.

Так unsafe это же нормально, у него есть своя область применения. Практически при любом interop от него никуда не денешься: компилятор может проверять только то, что он компилирует сам.

UFO just landed and posted this here

Servo как раз не очень удачный пример: он очень, очень старый, начал разрабатываться ещё до релиза Rust 1.0.

Уровень исходной(rustmustdie) статьи пробивает пол, хотя я и не фанат раста. Обычно то, что обозначается в статье, как zero runtime, называется bare metal, потому что именно эмбедерам оно и нужно. И ищется как bare metal rust.

PS: о кто-то обиделся и решил в карму плюнуть ) возможно было недопонимание, поправил, речь шла не о статье на хабре

Я бы даже сказал, что rustmustdie - это очень жирный наброс.

К примеру сборщик мусора std::rc::Rc;

Тогда в C++ есть как минимум 3 сборщика мусора (unique_ptr, shared_ptr, auto_ptr)

А кто смотрел тонкости лицензирования Rust этого? Не может с ним произойти то же что с Java?

Компилятор и стандартная библиотека очень даже свободные:
Rust is primarily distributed under the terms of both the MIT license and the Apache License (Version 2.0), with portions covered by various BSD-like licenses.

А что такого произошло с Java?

Были, а произошло-то что?

было много разного в его истории, чего хотелось бы избежать :)

(ну, если вы не корпорация с толстым кошельком)

Это всё, конечно, не самые приятные вещи, которые вообще никак не ограничивают 99,99999% разработчиков на Java. То есть проблемы с прагматической точки зрения пользователя языка не существует, проблема существует разве что этическая.

если вы школьник и пишете лабораторные работы - то без проблем. Если вы неуловимый джо или пишете бесплатный опенсурс - то тоже без проблем.

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

После прочтения возник такой вопрос: можно ли на Rust писать как на C? Т. е. используя по максимому стандартную библиотеку языка С, без напряга с borrow checker, не парясь над концепциями владения, оборачивая почти все в unsafe и т. д. и т. п.

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

UFO just landed and posted this here

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

P. S. На C# я когда-то занимался программированием как на С, просто нравилось так писать.

надо реализовать некоторую функцию на Rust (и желательно побыстрее, еще вчера), а стандартную библиотеку или плохо знаю, или не знаю

Звучит как то, чего нельзя делать ни в коем случае.


А так — сырые указатели есть, что ещё надо сишнику? :-)

Не, ну то, что сырые указатели есть, это уже хорошо. А как в Rust со всякими кастами? Как borrow checker на указателях работает?

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

Например для того, чтобы оттранслировать существующий C-проект, а потом, постепенно, переписывать его части, используя возможности Rust. Как режим BetterC в D.

Студент в упомянутой статье еще вроде бы взъелся на синтаксис в Rust. До меня немного не доходит почему. Я в разработке сравнительно немного (3 года) и системным программированием не занимался, но даже для того кто писал три года на TypeScript - синтаксис в Rust достаточно интуитивный.
Более того, чем больше пишешь на Rust, тем больше понимаешь, что синтаксис очень похож на TypeScript.

  • Структуры - интерфейсы с конструктором

  • Имплементации - все те же интерфейсы

  • Трейты - абстрактные интерфейсы

В синтаксисе все достаточно легко, даже те же стрелочные функции сделаны достаточно просто

fn main() {
    let n = 2;
    let x = 3;

    let string_concat = |x: i32, n: i32| -> String {
        x.to_string() + &n.to_string()
    };

    println!("{}", string_concat(x, n));
}

Да и сам студент почему-то вечно говорит про синхронный код, кой его в обычных задачах иногда бывает меньше, нежели асинхронного (HTTP-запросы, сокеты, файлы и так далее)

Также сборщик мусора о котором говорит учащийся - далеко не тот сборщик мусора, что например в JS или Python.

Автору респект за тщательный разбор материала

Из прочего:

  • Идея того, что в Rust отказались от null - просто превосходная, без него намного легче.

  • switch (тут он match) наконец-то стал выглядеть красиво, а не как огромное количество case

  • Идея с заимствованием понятна с самого начала, сделано для того чтобы никто не изменил переменную без нашего ведома

  • Там еще учащийся упоминал о том, что непонятно зачем теперь уровни вложенности, если все переменные будут все равно дропаться в конце. Они нужны чтобы не было вот такого:

fn main() {
    {
        let x = 32;
    }

    println!("{}", x); // Не скомпилируется
}

фигасе интуитивный. вот мне как ни разу не писавшему на расте не понятно - зачем println! восклицательный знак? ну предположим, что просто так функцию назвали. Но почему x.to_string() без & а &n.to_string() с ним? и зачем в println! первый аргкмент "{}"? это же явно не формат как в С-ной printf

Восклицательный знак потому что это макрос, а не функция. В первом приближении можно считать что и правда просто функцию так назвали. С аргументом тут тоже просто — это всего-то форматная строка, да не как в printf — но в printf самые плохие форматные строки, не удивительно что другие языки как могут придумывают своё.


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

> Но почему нельзя было сделать перегрузку для двух строк — для меня тоже загадка

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

А что в этом страшного?


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

Ну так и предлагаемая семантика это тоже позволяет.

в Rust же можно расширить существующий оператор - написать сложение с двумя владеющими строками?

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

Можно, но только в том же крейте в котором определены сами строки (т.е. в стандартной библиотеке).


Т.е. если бы в стандартной библиотеке появился вот такой код:


impl Add<String> for String {
    type Output = String;

    fn add(self, rhs: String) -> Self::Output {
        self + &rhs
    }
}

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

и новый бы чуть менее удивлял.

Вас бы действительно не удивляло, если бы оператор сложения дропал s2? :)

fn main() {
    let s1 = "Hello ".to_string();
    let s2 = "world!".to_string();
    let s3 = s1 + s2;
    println!("{}", s2); // oops: error[E0382]: borrow of moved value: `s2`
}

Но ведь он прямо сейчас "дропает" s1. Что, s2 чем-то принципиально отличается?


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

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

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

Синтаксически всё было бы верно, да. Идея в том, что если я вам даю дискету, чтобы вы с неё скопировали данные, я не хочу, чтобы вы её у меня забирали себе.

Но почему нельзя было сделать перегрузку для двух строк — для меня тоже загадка.

Потому что str является примитивным типом и потому методы на нём, включая реализацию трейта core::ops::Add, могут быть только в крейте core. Результатом подобного сложения должна быть выделяющая в куче память String, определение которой принадлежит крейту alloc, разумеется, зависящему от core. Написать реализацию такого сложения строк в core нельзя, потому что в этом случае core зависела бы от alloc, а циклические зависимости между крейтами недопустимы. Написать же реализацию сложения строк в alloc нельзя, потому что str — примитивный тип.


В любом случае, в примере выше проще было бы вместо сложения написать format!("{x}{n}"). И, кстати, к вопросу о том, почему это макрос, а не функция: с функцией вы не смогли бы интерполировать переменные.

Речь шла о сложении двух alloc::string::String, оператор для которых без проблем можно было бы определить в alloc::string, прямо рядом с оператором сложения alloc::string::String и str.

Вот вообще странные претензии.


зачем println! восклицательный знак?

А почему в питоне через % от форматной строки нужно аргументы перечислять?


и зачем в println! первый аргкмент "{}"? это же явно не формат как в С-ной printf

А почему он должен им быть?

А почему он должен им быть?

А зачем для вывода одной строки вообще какое-то форматирование? Почему нельзя просто передать string_concat(x, n) единственным аргументом в println!? Я хз как оно в расте, но в java подобное было бы индусским кода уровня if(value) return true; else return false;

По той же причине почему нельзя передать единственную строку в printf...


Кстати, вот вариант без форматирования:


stdout().write_all(string_concat(n, x).as_bytes()).unwrap();

Проще не получилось...

А зачем для вывода одной строки вообще какое-то форматирование?

Есть такой IT-анекдот: один мальчик передавал строки в printf без форматирования и строчка с процентом внутри оторвала ему голову.

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

претензия к восклицательному знаку была в том что я сперва принял его за некий оператор, оказалось что это признак макроса.

Про "{}" - во-первых непонятно зачем вообще тут форматирование - название макроса про формат ни единой буквой не говорит. Во-вторых - сами скобочки - что они означают? я не видел такого нигде.

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

Я не говорю что всё это неправильно, но явно не интуитивно.

будем считать что я просто слишком стар для раста, верните мне 90-е с ассемблером.

Во-вторых — сами скобочки — что они означают? я не видел такого нигде

Empty object (JS, json), empty dict (python), subtitute value (various string formatiing tools, e.g. Python's f-strings or Angular markup), empy tuple/cortege, empty map, name them all.

Но ведь про форматирование здесь только Python's f-strings or Angular markup , а раст вроде как на замену С - странно ожидать от С-шника знание питона и ангуляра.

Интуитивный язык должен позволять без проблем хотя бы понимать написанную программу. Я вот например не смог прочитать приведенный пример - поэтому не могу согласиться что "раст - интуитивно понятный".

Строки формата printf и иже с ними ни разу не интуитивны, и для того, чтобы их понимать, нужно читать документацию. И для формата, используемого в, в том числе, println! тоже есть документация.

А разве кто-то говорил про интуитивно-понятность?
Интуитивно-понятен только один интерфейс: женская грудь во время лактации. Всему остальному нужно учиться.

так и пользованию грудью младенцы (и мамы) учатся )))


на самом деле есть разница, конечно, между интуитивностью разных языков, например:


  • sql (не считая современных заворотов вроде работы с json) можно один раз выучить, потом не трогать пару лет, потом написать запрос.
  • с перлом через полгода перерыва приходится лезть в справку интернет по всяким мелочам.

(разумеется, вышенаписанное индивидуально, сужу исключительно по себе, для кого-то может быть ровно наоборот)

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


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


С sql тоже не все так просто, если выйти за рамки простой пары select…where: от разных по производительности реализаций джойнов до аггрегаций и фактического порядка выполнения операций.

ээ, вобще-то я как раз с утверждения crackidocky "синтаксис в Rust достаточно интуитивный." и началась эта ветка.

Да, простите, этот был невнимателен при поиске.

Про "{}" — во-первых непонятно зачем вообще тут форматирование — название макроса про формат ни единой буквой не говорит. Во-вторых — сами скобочки — что они означают? я не видел такого нигде.

В языке C# метод Console.WriteLine тоже ничего про форматирование не упоминает, но таки делает его. И скобочки тоже явно оттуда, только там ещё и номер аргумента указывается: Console.WriteLine("{0}{1}", n, x);

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

Интуитивный? Не, ну вы издеваетесь.

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

Скажу неожиданный минус Раста - отсутствие нормальной поддержки сишных строк. Подавляющее большинство нативных библиотек имеет Си совместимый интерфейс. А в расте для стандартных CStr/CString даже трейт Display не реализован. И как литерал их из коробки записать нельзя. Предлагается конвертировать строки туда сюда на каждый чих. Что мешало добавить в стандартную библиотеку несколько функций?

Ирония в том, что си-строки в Rust поддерживаются лучше, чем в самом си - есть хотя бы собственный тип с базовыми методами, а не просто глупый массив символов. В принципе, и без этих методов и типа жилось бы не сильно хуже, учитывая количество возможных кодировок строк, из-за которых все равно нужно спускаться на уровень глупого массива байт (да, это ответ на вопрос, почему нет Display и прочего визуала).

Намного важнее сам принцип: язык Си позволяет полностью отказаться от возможностей стандартной библиотеки

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

> Но это бы лишний раз показало, что преподаватель, который влил эту чушь в голову студентам МГУ, не просто находится не на своем месте, он вообще ничего не смыслит в системном программировании.

Когда оценивают подобное утверждение, надо понимать минимум две вещи:

1. Чему равно «все» = «универсальное множество» в рассмотрении. Потому что всегда есть, например, где-нибудь какой-то наспех сляпанный одним студентом язык, который даёт 1/4 того, что есть в C89, при этом точно так же не требует стандартной библиотеки, но достаточен для написания драйверов. (Или, возьмём пример ещё грубее, язык, использованный марсианами. Мы про них ничего пока не знаем.) Естественно, он не рассматривается, и «все» будет включать «все достаточно известные, чтобы попасть в рассмотрение», и это не будет являться ошибкой автора.

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

В сумме, позиция автора статьи показывает или его некомпетентность в вопросе анализа источников — что недопустимо для обладателя высшего естественнонаучного образования, или же существенную личную неприязнь к конкретному преподавателю. Оба фактора не позволяют положительно оценить ни его, ни статью. Надеюсь, что автор осознает и исправится.
2. образование отстаёт от реальности — поправил
если хотите актуальных знаний не надо туда вообще лезть

я вот может не знаю, образование учит анализировать источники?
И ещё:

> Настало время реализовать вывод «Hello, world!» в стандартный поток вывода! \<Не забыть изменить на менее глупую фразу перед публикацией>.

1. Лучше использовать более привычные пометки типа XXX, TODO… — по ним легко искать.

2. А что глупого-то в «Hello world»?

Уж простите, что не про Rust.

Полагаю, это отсылочка к "убрать перед публикацией" из квеста, о котором недавно рассказывали на Хабре: https://habr.com/post/689116/

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

Очень надеюсь, что через некоторое время автор скажет что-то на подобии "Расходимся, это была шутка".

Прочитал. Оценил важность делать syscall "без нифига" (это действительно нужно? Для C? И для условного JavaScript-а тоже (как он только ещё живёт-то без этого)?).

Далее ! САРКАЗМ !:

Впечатление как об каком-то обществе защиты жуков-выберите-любой:

  • А-а-а, общество куропаток назвали нашего жука хуже бабочек-однолеток! Как они посмели!

  • Однако наш жук лучше: посмотрите, какие у него шейные мышцы!

  • Конечно же, в интернете кто-то неправ. Но почему все наезжают на нашего жука! Вот прям все-все-все!

Это сильно напоминает стенания: про наших жуков забы-ы-ы-ы-ли!!! Как вы могли-и-и???

конец сарказма.

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

Возможно, будущие статьи писать без противопоставления с другими языками. В стиле:

Посмотрите, какие прикольные штуки умеет Rust? Он может работать и без стандартной либы!

Возможно, будущие статьи писать без противопоставления с другими языками. В стиле:

мне кажется, вы неправы. «какие прикольные штуки» неинтересны в отрыве от существующего ландшафта, быть может эти прикольные штуки давно есть в других языках, а может быть по ним там давно сложился консенсус, что это bad practice.


как раз важно и интересно читать, почему в golang принята одна модель обработки ошибок, а в java — другая; какие у каждого подхода есть достоинства и недостатки.

Соглашусь с Вами в контексте обсуждения ПРАВИЛЬНЫХ (или рекомендуемых) подходов - и это действительно интересно. Хотя тут на первый план выходит компетентность сравнивающего: насколько он (реально практикующий) профессионал сразу в двух (подчеркну - очень разных) языках.

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

Только проблема всей статьи в другом:

Реализация предпосылки сразу убивает и C и Rust одним выстрелом: Давайте напишем программу на C (а потом и на Rust), которая есть "реализация ... под Linux i386". Вы серьёзно? А если нужно под Dos/Windows/MacOSX/Qnx/..., то программа на C/Rust превращается в тыкву?

Язык C слегка подразумевает, что можно скомпилироваться под разные платформы. Полагаю, что для Rust - аналогично. Здесь исходный текст (отмечу - не бинарный код) приколачивается гвоздями и к операционной системе и к типу процессора. Представьте, что java-программисты при написании кода требовали бы Linux i386 (иначе - работать не будет)?

Поэтому (с моей скромной точки зрения) статья вообще не имеет смысла. Даже в контексте "прикольных штук". Это даже bad practice нельзя назвать.

Зачем это тов. Столярову - понятно: он пишет книги, он учит студентов (короче, зарабатывает человек). Зачем это тов. humbug? Либо попытка заработать (очень мудрёная), либо паранойя "про нас все забыли!!!!". И последний вариант возвращает нас к пред-предыдущему посту. Повторюсь - это лишь частное мнение.

Я бы хотел, чтобы в МГУ (самом МГУ!) ученые и студенты были открыты к познанию. Ведь в этом и есть суть университетов, нет? Слишком многого хочу?..

хмм .. а представьте что завтра к вам университет придет и скажет "мы хотим, чтобы вы открыли нам глаза и пришли к нам на кафедру. Будете у нас вести курс, вместо вот этого косного и закрытого к познанию нехорошего человека" - они многого хотят или норм ? :)

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

А я вот не очень понял, почему rustc_codegen_gcc генерирует нечто другое, чем до его использования? В чём именно различия будут? Спасибо.

Автору заслуженный плюс. И за статью, и за мотивацию к ее написанию
p.s. сам ни разу не кодер, ни разу не знаком с rust, но прочел на одном дыхании вместе со всеми спойлерами :)
Считается, что 93.9% программистам именно такое поведение (автоматическое включение std и прелюдии) и требуется.
Тем не менее, для остальных 19% программистов предусмотрен режим отключения стандартной библиотеки с помощью атрибута #![no_std]
Вы же не думаете, что я тут беру статистику с потолка?
Эээ… Нет, конечно, не думаем ни в коем случае! :)
Ну это же сарказм. И первое, и второе, и третье.

Кстати, раз уж прописали panic = "abort", то extern "C" fn eh_personality() {} не нужна.

Finished dev [unoptimized + debuginfo] target

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

«МГУ сделал замеры -- Rust должен умереть» было бы еще драматичней)

Было занимательно прочитать!

Кстати, если рассматривать не только Rust, то окажется, что на поверку утверждение А.В.Столярова ещё более ограниченное в плане рассмотрения.

Ведь помимо традиционных высокоуровневых языков программирования, "уникального" C и языков ассемблера есть ещё Forth, чей "рантайм" для любой конкретной архитектуры железа программируется в том числе на голое железо даже на языках ассемблера без особых проблем с нуля за несколько дней работы (уточнение: при должном знании целевой архитектуры), после чего можно наращивать кодовую базу программируя в сравнительно высокоуровневом ключе. Более интересная эквилибристика - это написать форт-машину под множество архитектур, тут наиболее успешным стал проект CollapseOS. Еще из примечательного, этот язык программирования используется в загрузчике FreeBSD.

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

Коллеги кто-нибудь может мне объяснить "за феномен Forth".
Часто вижу вот такие вот восхваления про форт и блоги отдельных исследователей форсящих его.

Но язык 1971 года не ставший популярным (да ещё и построенный на стековой машине - моде 1970х годов) меня очень смущает.
Кто-то из инженеров может пояснить: есть что-то реально стоящее в языке (ну условно Haskell можно изучить для полезного расширения кругозора, Rust - для полезного изучения кругозора и для программирования) для его изучения или просто у языка есть группа преданных фанатов?

Надеюсь, что Вам ответят, так как ситуация парадоксальная - упрощая, все люди делятся на тех, кто Форт не знает; тех, кто от него фанатеет и наконец тех, кто его ненавидит.

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

  1. Это язык программирования, машина исполнения которого понятна. В мире, где для одной из самых популярных компьютерных архитектур даже язык ассемблера в каком-то смысле "компилируемый", а не транслируемый (здравствуй, микрокод x86), где даже виртуальные машины интерпретируемых и JIT-компилируемых языков сложны, по-моему это приятная "отдушина".

  2. На более высоком уровне (как самого языка, так и владения им) Форт предлагает метапрограммирование, которое резко отличается от ООП в стиле C++ (и всех его потомков)

Таким образом, язык похож на Лисп, но с некоторыми фичами (низкоуровневость, миниатюрность и исполнение на голом железе - очень удобно для микроконтроллеров; ещё есть интересные свойства из-за конкатенативности, так по идее можно например упрощать выражения). Также эта простота позволяет использовать его как основу примитивных DSL-процессоров, которые могут, например, обладать повышенной надёжностью (чем проще система, тем надёжнее) и использоваться, скажем, в космосе, или работать в наноботах, и т.п. нетривиальные задачи. Также идейный потомок Форта реализован в контроллере практически любого принтера (PostScript, привет!) и вообще это очень неплохо для встраиваемой техники.

Есть и, казалось бы, очевидные недостатки: чаще всего программы на Форте падают от одной-единственной ошибки, многие программы с нуля пишутся как головоломка. Но тут важно понимать, что это не объективная проблема, а несовместимость с современным ИТ и методологией разработки - но и сейчас бывают и такие программы, в которых не должно быть ошибок, а вместо "программ с нуля" (каждая из которых в 80ые-90ые, как правило, была от одного вендора) иногда правда лучше работать с именованными функциями (словами).

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

Но повторю, я скорее из "преданных фанатов" :D , но старался расписать как можно объективнее.

> Но язык 1971 года не ставший популярным (да ещё и построенный на стековой машине — моде 1970х годов) меня очень смущает.

Он не станет популярным по крайней мере пока современная архитектура процессоров со всеми этими out-of-order довлеет над остальными. Потому что компиляция Forth, где почти всё это вызовы билтинов, не способствует скорости на таких процессорах.
Но зато где-нибудь в космосе, где предсказуемость и надёжность (и однозначность!) всех действий важнее — там ему вполне место. Потому что в нём чётко видно, что из чего произошло, в отличие от C, C++, Rust и прочих, где компилятор перерабатывает код до неузнаваемости. Имея управляющий компьютер, у которого и аппаратно каждое действие чётко и ясно — прочитал ячейку, сделал операцию, записал ячейку (а если надо — повторение каждой машинной команды с проверкой результата, сравнение результатов нескольких одновременно работающих блоков, и т.д.), и программно — что написали, то и выполняется — можно надеяться на отсутствие сюрпризов и, что главнее, на защиту от них.

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

> Кто-то из инженеров может пояснить: есть что-то реально стоящее в языке

Большинству сейчас — Forth стоящий не практически, а как одно из средств замыкания понимания теории. Грубо говоря, программист, который знает один процедурный язык, затем Forth и LISP, вполне может сказать, что он «видел всё» в плане основных подходов; а также то, что он показывает, как живую интерактивную компилирующую среду можно вогнать в десяток килобайт. Да-да, кругозор. Поэтому — можно всю жизнь на нём ничего не делать, но желательно понять подход.

> а ещё и построенный на стековой машине — моде 1970х годов

Стековых машин и сейчас полно — смотрим хотя бы на JVM или дотнет. И это не 70-е. Это действительно удобная модель, даже если потом её переложит на регистры.

PS: Сравнивая с соседним ответом, я ни в одной из групп: не игнорант, не фанат и не хейтер. В школе написал свою реализацию (под Агат) и она даже завелась, хоть и медленно;) но сейчас знание про него тупо впиталось в общее представление и более не интересно.
Он не станет популярным по крайней мере пока современная архитектура процессоров со всеми этими out-of-order довлеет над остальными

гхм, форт в разы старше массового out-of-order, так что явно не в этом причина непопулярности

> гхм, форт в разы старше массового out-of-order, так что явно не в этом причина непопулярности

Почему не в этом? Компилированный («шитый») код на Forth неэффективен на процессорах с OoO, и это существенная причина.
> Еще из примечательного, этот язык программирования используется в загрузчике FreeBSD.

Сейчас оттуда таки постепенно выносят Forth и вносят Lua. Всё-таки BTX это не голое железо и загнать туда сотню килобайт достаточно легко.

Моё уважение автору!) Статья получилось подробной, интересной и захватывающей! На самом деле да -- не стоит следовать советам знаменитых людей, самому не проверив информацию. В современном мире вообще следует подвергать всё сомнению

Я в этом самом МГУ учился и Столярова видел.

Мне очень интересно, когда и в какой момент ВМК МГУ стал авторитетом в области программирования.

Когда я учился там почти 20 лет назад, я наблюдал давление на тех, кто пытался принести что-то новое. Учитывая, что имена не поменялись, непонятно с чего это давление должно было исчезнуть.

Буду рад увидеть какие-то значимые достижения МГУ (и в частности ВМК) в практической области программирования. Аутсорсное батрачение на западные компании (что преподносилось как очень большое достижение) просьба не показывать, не релевантно.

Не могу не попытаться призвать в тред товарища @3Dvideo- памятуя о прослушанном (к своему стыду, наполовину) курсе его авторства, думаю, их кругу будет что ответить.

Что мне иногда раздражает, так это то что многие говорят под капотом rust использует много unsafe, и что нельзя превратить unsafe в safe.

Хотя вот пример как из превратить unsafe в safe и получать PROFIT :-). Привожу адаптированный код хеш таблицы из библиотеки hashbrown:

pub struct RawTable<T, A: Allocator + Clone = Global> {
    table: RawTableInner<A>,
    // Tell dropck that we own instances of T.
    marker: PhantomData<T>,
}

pub struct RawTableInner<A> {
    bucket_mask: usize,
    ctrl: *const u8,
    growth_left: usize,
    items: usize,
    alloc: A,
}

pub fn get<F>(&self, hash: u64, eq: F1) -> Option<&T>
where
    F: FnMut(&T) -> bool,
{
    match self.find(hash, eq) {
        // bucket = *mut T
        Some(bucket) => Some(unsafe { &*bucket }),
        None => None,
    }
}

Прикол в том что вроде бы как RawTableInner хранит сырой указатель на аллоцированную память и полностью небезопасен. Но далее привязываем данную таблицы к RawTable + PhantomData что говорит компилятору что у нас владеющая структура. Потом определяем метод get, который внутри использует метод find. Find возвращает сырой указатель. Но!!! Мы ведь определили метод get у &RawTable, а также привязали выходную ссылку на значение к времени жизни самой RawTable, то есть выходная ссылка будет всегда валидна, так как нельзя вернуть ссылку на удаленную таблицу.

То есть, метод find который возвращает полностью небезопасный "сырой указатель" который может существовать даже после удаления RawTable, и по определению unsafe, превратился полностью в safe. Так как с помощью метода get мы явно привязали жизнь сырого указателя к жизни RawTable. Кроме того мы привязали его не просто к таблице. Мы еще и заблокировали изменения самой RawTable, пока существует на него ссылка. И все это в 10 строк кода (функции get).

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

Именно это свойство — zero runtime — делает Си единственным и безальтернативным кандидатом на роль языка для реализации ядер операционных систем и прошивок для микроконтроллеров. Тем удивительнее, насколько мало людей в мире этот момент осознают; и стократ удивительнее то, что людей, понимающих это, судя по всему, вообще нет среди членов комитетов по стандартизации (языка Си)…

— А. В. Столяров

Нет взаимосвязи между наличием у языка runtime и возможностью реализации на этом языке ядер операционных систем и прошивок для микроконтроллеров. Я знаю о проектах на диалектах Lisp, но, наверняка, есть проекты и на других языках. На Lisp написаны: Mezzano, Loko Scheme, Maker Lisp, LisPi, PilOS, PICOBIT и т.д.

Хотелось бы выразить робкую надежду на то, что пока сообщество Rust самозабвенно борется против C за право занять место царя горы традиционного софта на основании малозначимых свойств языка, где-нибудь в стороне от этой эпической схватки вырастут более изящные системы с более простыми, эффективными, легковесными и разумными API и IPC...

на основании малозначимых свойств языка

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

А что, раньше не было такой возможности?

UB раньше было, в неожиданных местах.

Почему в неожиданных, вроде, известно, как программировать, чтобы UB не было? И почему предполагается, что программировать можно было только на C или C++?

Почему в неожиданных, вроде, известно, как программировать, чтобы UB не было?

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


почему предполагается, что программировать можно было только на C или C++

Эммм… вы статью читали? Она вся про Rust vs C(++).
А свой комментарий — ту его часть, что породила эту ветку — тоже читали?

Эмс... Я, в основном, высказался о том, что программировать операционные системы можно не только на языках с нулевым runtime... Следовательно, нулевой runtime не является важным свойством для этого.

Из контекста не до конца понятно, мы говорим о принципиальной возможности написать стабильный софт до появления в природе Rust или о цене такой работы?

Вроде как, люди писали вполне стабильный софт даже на ассемблере. То есть, принципиально это возможно.

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

Собственно, в итоге и возникает мой вопрос: насколько значимо это свойство нулевого runtime? Оно нужно, чтобы что? Чтобы в ядре можно было программировать? Но в NetBSD можно в ядре программировать на Lua 🤷🏼‍♂️

Rust интересный язык, конечно. Я просто пишу о том, что существуют и другие подходы.

Я, в основном, высказался о том, что программировать операционные системы можно не только на языках с нулевым runtime...

Но ветку-то породило совершенно другое ваше высказывание.


Из контекста не до конца понятно, мы говорим о принципиальной возможности написать стабильный софт до появления в природе Rust или о цене такой работы?

Смотрите, принципиально протон нестабилен. Но горизонт этой нестабильности на порядки (много порядков) превышает возраст вселенной.
С практической точки зрения это значит, что он абсолютно стабилен.
Так вот, принципиально можно писать все только на ассемблере, или имея всего одну машинную инструкцию (OISC)… И даже и то и другое одновремённо.
А практически? Возьметесь переписать ну, хотя бы, ядро Колибри на OISC-ассемблер и доказать надежность написанного кода — или переобуетесь в прыжке прозреете, внезапно осознав, что некоторые вещи просто бессмысленны по своей сути?


Можно писать эффективные и безопасные программы на языках с ненулевым runtime, и эти языки существовали до появления Rust

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


насколько значимо это свойство нулевого runtime? Оно нужно, чтобы что?

С ним проще строить realtime-системы и писать ядерные процедуры.


но в NetBSD можно в ядре программировать на Lua

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


Я просто пишу о том, что существуют и другие подходы.

В целом мы все пишем о многом.
Это не делает любое высказывание — корректным. И одно из таких некорректных высказываний, собственно, эту ветку и породило.

Вы слишком быстро жонглируете метафорами. Предлагаю опираться на факты.

  1. Можно ли писать стабильный софт не на Rust? Очевидно, можно, примеров уйма.

  2. Можно ли писать стабильный софт на Си? Можно, примеров множество. Многие примеры летают в космосе. Код на Си можно верифицировать, например, проверкой моделей. Это активно применяется на практике.

  3. Можно ли писать операционные системы на языках с ненулевым runtime? Можно, примеров много. И не очень понятно, как именно runtime усложняет эту работу.

  4. Можно ли писать hard realtime приложения на языках с ненулевым runtime? Можно. Примеров не так много, но они есть, и некоторые подходы выработаны. Есть специальные сборщики мусора, есть техники управления потоками и памятью. Они специфичные, и влияние runtime тут, конечно, нужно учитывать, но я бы не сказал, что это прям вот сильно сложнее, чем программировать realtime-системы на Си.

Итак. Дальше у нас идёт основной вопрос: является ли нулевой runtime значимым свойством языка? Вы же малозначительность этого свойства подвергаете сомнению? Вроде, пункты 1-3 никак не зависят от наличия runtime. Пункт 4... Ну, как бы, с одной стороны, да. Если языку нужен runtime, то при разработке hard realtime приложений возникают тонкости. Но, с другой стороны, runtime может быть заточен под hard realtime задачи, как, например, RTSJ (rt spec for java), и запрограммировать необходимое поведение системы можно.

Соответственно, вопрос: если можно и так и этак, то так ли принципиально важен нулевой runtime? Понятно, что можно постулировать важность чего угодно, хоть макаронного летающего монстра, но есть ли для этого какие-то материальные основания?

Это не метафоры, это иллюстрации.


основной вопрос: является ли нулевой runtime значимым

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


пока сообщество Rust самозабвенно борется против C за право занять место царя горы традиционного софта на основании малозначимых свойств языка

В нем вброшено сразу два ложных постулата, выделены жирным.
Один из них и породил ветку.
А вы пытаетесь сделать вид, что ничего такого не было, даже когда вам прямо об этом говорят — несмотря на то, что доказательства обратного висят перед глазами у любого мимокрокодила — и подменить тему.
Не надо так делать.


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

А почему не отсутствие UB, о котором каджит писал выше по ветке?


Кстати, список ваш — типичный пример "трех да". Правда, не со всеми собеседниками это работает.
Пункт 1 говорит о всей совокупности софта, а уже пункт 2 — подменяет просто софт на Си — софтом, в котором вопрос цены стоял в последнюю очередь (и который в генеральной совокупности составляет исчезающе малую долю).
За контрпримером даже ходить далеко не надо: вот уже пару недель ядерный kvm регулярно падает после примерно суток работы, жалуясь на списки: указатели, мол, не туда указывают, ни add ни delete не сделать. Можете себе представить, чтобы на списки пожаловался, например, Erlang или Python?


Пункт 3 — начисто игнорирует, например, прерывания (процедура обработки прерывания должна быть как можно более короткой, по сути, ее дело — разгрузить железные буфера, прочитать и записать регистры, и поставить в очередь сам обработчик — пока мусор собирается, сеть теряет пакеты, а ssd простаивает). Да и в целом с работой с железом дружит плохо — и если на x86_64 это можно скомпенсировать частотами (быстрее тормозить), то на Cortex-M0 может просто парализовать функционирование устройства.


Соответственно, вопрос: если можно и так и этак, то так ли принципиально важен нулевой runtime?

Важно отсутствие UB
Важна предсказуемость
Важна доказуемость правильности выполнения — не условное покрытие тестами, а математическая верифицируемость
Важно писать меньше кода в целом, писать больше бизнес-кода, который проще охватить взглядом и понять — вместо обвязок вокруг UB и бесконечной ловли исключений


И только в отдельных случаях выходит на первое место zero-runtime. Но это место, пока что, по крайне мере, лежит в основе всего остального пирога.

А почему не отсутствие UB, о котором каджит писал выше по ветке?

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

Затем, я отвечал на высказывание о том, что вот теперь-то на Rust мы заживём и начнём писать стабильный код. Будто до появления Rust мы не писали стабильный код. На Erlang, упомянутом Вами, написано довольно много стабильного кода, и на Си тоже. Есть разные способы формальной верификации и обеспечения стабильности кода. И для Си тоже существуют методы формальной верификации. Вот, известный пример: https://frama-c.com/

Тот подход, который предложен в Rust не единственный. Я говорил лишь об этом.

Пункт 3 — начисто игнорирует, например, прерывания (процедура обработки прерывания должна быть как можно более короткой, по сути, ее дело — разгрузить железные буфера, прочитать и записать регистры, и поставить в очередь сам обработчик — пока мусор собирается, сеть теряет пакеты, а ssd простаивает). Да и в целом с работой с железом дружит плохо — и если на x86_64 это можно скомпенсировать частотами (быстрее тормозить), то на Cortex-M0 может просто парализовать функционирование устройства

Почему игнорирует? Наоборот, runtime и сборщик мусора специально так проектируются, чтобы можно было быстро обрабатывать прерывания. Для этого есть специальные решения. Вот небольшой обзор от Google:

https://www.researchgate.net/publication/4075178_A_hard_look_at_hard_real-time_garbage_collection

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

Кроме этого, некоторые runtime для hard real-time приложений позволяют формировать задачи, которые выведены из-под сборки мусора, с соответствующими ограничениями на допустимый код этих задач.

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

Я не говорю, что это идеально. Я всего лишь утверждаю, что альтернативные подходы существуют. Достоинство их очевидно - существенно меньшее время разработки. И, недостаток, конечно, очвеиден тоже - нужно очень тщательное проектирование runtime и семантику языка, в которых появляется множество тонкостей, которые нужно согласовать. Но, повторюсь, есть примеры, которые показывают, что это возможно. Вот один из них: https://www.irisa.fr/prive/talpin/papers/fidji03.pdf

За контрпримером даже ходить далеко не надо: вот уже пару недель ядерный kvm регулярно падает после примерно суток работы, жалуясь на списки: указатели, мол, не туда указывают, ни add ни delete не сделать.

Контрпримером для чего? Странно слышать такое от человека, который так горячо приветствует формальные доказательства, и который, гипотетически, должен разбираться в логике первого порядка. Я разве написал, что любая программа на Си стабильна?

Кроме того, в Rust есть проблемы с динамическими структурами данных. Если судить вот по этому (а ничего более полного у меня найти не получается) https://rust-unofficial.github.io/too-many-lists/, даже банальный двусвязный список требует использования unsafe-конструкций. То, что проблемы с реализацией эффективных структур данных есть, подтверждает и чтение исходного кода Redox, в котором структуры данных, мягко говоря, топорные.

Почему Вы уверены, что kvm удастся реализовать на Safe Rust? Я читал исходники kvm, и немного правил их под себя, там используются довольно сложные динамические структуры данных для обеспечения производительности. Можно ли их запрограммировать на Rust с сохранением гарантий?

Важно отсутствие UB

Важна предсказуемость

Важна доказуемость правильности выполнения — не условное покрытие тестами, а математическая верифицируемость

Это, конечно, важно. Но достижимо ли на практике. Можете посмотреть на объём формальных математических доказательств корректности простейших алгоритмов на каком-нибудь Coq, и прикинуть, сколько усилий нужно, чтобы доказать корректность того же KVM. А потом обнаружить, что аксиоматика была некорректной... Вот на примере compcert: https://sf.snu.ac.kr/sepcompcert/compcertbugs/

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

Все еще говорите о чем-то своем, не заметили?

Естественно, я говорю о своём. А что, существуют люди, которые способны говорить о чужом? Но проблема не в этом, а в том, что, как мне кажется, Вы пытаетесь перевести спор на свойства моей личности.

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

P.S. Ну, и, кстати, про тесты тоже есть своя математика, а именно, PCP-теорема. Поэтому противопоставлять тесты и математику, ну, как-то, тоже странно...

Вы понимаете разницу между безусловным доказательством и вероятностным?

Понимаю. Но разве речь была о том, что разницы нет? Речь была о том, что у тестов есть своя математика.

И термин "безусловное" доказательство несколько неадекватен. Правильнее говорить "логическое", потому что те доказательства, которые Вы подразумеваете, как минимум, обусловлены правилами вывода (которые, кстати, во многих языках, и Rust не исключение, ненадёжные: см. https://counterexamples.org) и набором аксиом, которыми описывается предметная область. И этот набор тоже может содержать ошибки: см., например, баги в CompCert.

Да вроде бы все знают, что надо делать как правильно, а как неправильно — не делать.
Только вот отсутствие проверок на NULL, отсутствие проверок размеров массивов, отсутствие инициализации переменных перед чтением, неверное использование примитивов синхронизации (например, в одном месте lock(a) lock(b) unlock(b) unlock(a), а в другом lock(b) lock(a) unlock(a) unlock(b)) или вообще их отсутствие, overflow/underflow из-за использования неподходящих типов данных и т.д. встречаются даже в серьёзных проектах.
Люди слишком ленивые и рассеянные, чтоб постоянно помнить про всё это (и не использовать copy-paste), а компьютеры делают точно то, что им сказали, а не чего от них на самом деле хотели…

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

Так это ж только примитивные ошибки, а бывает и сильно более забористые штуки, например правила алиасинга — сможете ли назвать что можно, а что нельзя алиасить согласно стандарту (любому, на ваш выбор)?
Или, например, знаменитый fast inverse square root (в оригинальном виде) может у вас просто не заработать, потому что такое кастование указателей — UB, будьте добры использовать union, в противном случае компилятор туда имеет право вставить хоть abort(). Согласитесь, неожиданно ведь будет если 20-летний код у вас внезапно откажется работать?
UFO just landed and posted this here

Компиляторы Си постоянно тестируют на регрессию огромным количеством тестов, среди которых есть и fast inverse square root. Сомневаюсь, что поломка 20-летнего кода пройдёт незамеченной и окажется для пользователей внезапной.

Гипотетически, такое возможно. Практически, думаю, вероятность такого события настолько близка к нулю, что про Си забудут раньше, чем она реализуется.

> Компиляторы Си постоянно тестируют на регрессию огромным количеством тестов, среди которых есть и fast inverse square root.

Если вы так утверждаете, не будете ли любезны привести URL (для GCC или Clang)? Искренне интересно посмотреть на тест.

Насколько я понимаю, для того, чтобы иметь (хотя бы теоретическую) возможность zero runtime, язык должен:

  • Не иметь неубираемых внешних зависимостей (например, интерпретатора или сборщика мусора). Тут возникает вопрос, считать ли отсутствием зависимостей случай статической линковки. В случае этой статьи, очевидно, автор под zero runtime имеет ввиду возможность близкой к 1:1 трансляции в ассемблер. Это, на мой взгляд, не совсем верно, но ладно.

  • Не иметь добавляемого библиотечного кода, т.е. иметь так называемые zero-cost abstractions. Тоже спорно, но ладно, автор так решил.

  • Третье условие - языком должно быть возможно пользоваться на этих условиях.

Итак, отвечает ли Раст этим условиям? Вроде отвечает. Обязан ли он быть в этих условиях более эффективным по машинному коду, чем С? Ну типа автор оригинальной статьи это подразумевает, но непонятно с какой стати. В таких условиях практически любой язык - это будет вариант С, только с другим синтаксисом + генерируемый или библиотечный код (типа тех же методов итераторов), который можно использовать или нет.

Почему циклы, ветвления, арифметические операции (хотя тут есть особенность из-за defined/undefined behaviour), вызовы функций должны отличаться сколько нибудь заметно? Настолько ли это важно, что прям из-за трех лишних байт в ассемблере в bare metal mode Раст должен прям умереть?

Спасибо за статью, помнится в 90ых какой-то профессор захейтил проект Торвальдса. Неговоря уже про классику "640к всем хватит". Так что ненадо принимать слишком близко к сердцу весьма спорные высказывания всяких... будь то профессор МГУ или даже Маск.

А этот историк, которого с руками женскими в реке выловили - но тоже ведь из МГУ?

Хаха круть, просто завидуют расту и аниме сообществу

Здравствуйте, @humbug, я постепенно пишу бесплатный курс по Rust на Stepik с кучей теории и практики. Telegram: https://t.me/dmitrii_dem Я был бы очень рад получить совет по поводу того как можно улучшить. Уже есть порядка 20 уроков с10 шагов в каждом.

А минусы-то за что? Я пытаюсь сделать нечто полезное для сообщества и выживаю как могу. Связаться же как-то надо, чтобы плохо не получилось.

Попробуйте написать автору в личку.

P.S. Лично от меня вам плюс за труды. Успехов в разработке курса!

Оргигинальная статья бред основаная на ограниченных знаниях

Увы. Такова психология людей. При появлении нового вокруг этого нового куча мифов и невежества. Rust можно продвигать только оспаривая такие вот ложные глупые заявления. От этого никуда не деться. Так что, нужна статья, разбивающая все остальные аргументы того парня. Лишь так работает просвещение. По другому никак. А вы очень нужное дело делаете! Пожалуйста, продолжайте разгонять мрак невежества! Просим! Заклинаем! Умоляем!

Продолжайте, пожалуйста ваше жизненно важное дело. Добейте все "аргументы" того паренька из МГУ.

Sign up to leave a comment.

Articles