OSDay 19 или почему еще жив язык Си

    Недавно (10-11 июня) в Москве прошла очередная научно-практическая конференция OSDay. На этот раз конференция проходила в математическом институте им. В.А. Стеклова РАН. Формально она была посвящена инструментам разработки операционных платформ и системного программного обеспечения. Как обычно, темы, затрагиваемые на конференции, не ограничились формально заявленными, а поднятые вопросы рассматривались с разных сторон и обсуждались различные подходы к их решению. Различные взгляды и подходы — это, на мой взгляд, то, что выделяет конференцию среди остальных. Так, например, в конце второго дня конференции, буквально под занавес, Дмитрий Завалишин ( dzavalishin ), один из организаторов, спровоцировал бурную дискуссию, о том, что язык программирования Си вообще-то устарел и разрабатывать (в том числе и операционные системы) нужно, как минимум, на языках с управляемой памятью. Свое видение об этой дискуссии и других интересных мне темах, поднятых на конференции, я изложу в данной статье. Кому интересно прошу под кат.

    Выставка


    Начну не с обзора докладов, а с выставки, которая является частью конференции. Несколько компаний показали свои разработки в области системного ПО. В основном это операционные системы, но, например, компания РЕД СОФТ кроме ОС представила СУБД “РЕД База данных” основанную на проекте “Firebird”. Об этой СУБД я уже упоминал при обзоре одной из прошлых конференций OSDay. Новой информацией для меня стало то, что она портирована на архитектуру Эльбрус.

    Поддержка архитектуры Эльбрус была заявлена в продуктах и у других участников выставки. Информация о том, что ОС Альт-Linux исполняется на процессорах Эльбрус, конечно, не стала для меня новостью. Сотрудники Базальт-СПО, как обычно, привезли стенд на базе Эльбруса и продемонстрировали работу своей ОС на этой платформе. А вот то, что на баннере QP ОС, о которой я также несколько раз уже рассказывал в обзорах конференции, заявлена поддержка поцессоров Эльбрус, меня удивило. Ведь мы приложили немало усилий чтобы портировать Embox на данную архитектуру, о чем также писали на хабре. Выяснилось, что к сожалению, это не полноценный порт под архитектуру e2k, запуск был осуществлен в режиме трансляции команд x86, который, как известно, присутствует в процессорах Эльбрус.

    Поддержка различных аппаратных платформ была фишкой всех участников выставки (за исключением компании РусБИТех -Астра, но у них, как известно, своя ниша). РЕД СОФТ показал свою РЕД ОС (если я правильно понял, то это наследник ГосЛинукс, который внесен в реестр отечественного ПО) на RaPi. У QP ОС была заявлена поддержка ARM. Но безусловно, самым кросс-платформенным выступил Альт-Линукс. Коллеги показали работу не только на отечественных Эльбрусе и Байкале, но и, например, на такой относительно редкой архитектуре как RISC-V.

    Информационная безопасность


    Тема безопасности ПО очень широкая. На конференции несколько раз объясняли, что существуют несколько различных типов безопасности, точнее определений, что же такое безопасность. Происходят они от английских safety, security, reliability и так далее. Поэтому докладчик обычно говорил, о какой именно безопасности идет речь в данный момент. Хотя все сходились во мнении, что трудно говорить об информационной безопасности (security), если не обеспечена функциональная безопасность (safety).

    Условность разделения на security — safety была хорошо заметна на секции, посвященной информационной безопасности. Например, Александр Попов ( a13xp0p0v ), разработчик ядра Linux, который на предыдущей конференции выступал с докладом “Как STACKLEAK улучшает безопасность ядра Linux”, представил доклад “Карта средств защиты ядра Linux”, и на карте видно, что ключ к информационной безопасности лежит в области качественного ПО. Ведь большинство проблем безопасности являются стандартными: переполнение буфера, переполнение стека, не очистка стека при возврате из системного вызова и т. д. Посмотреть его проект можно на github. Вчера опубликовали на хабре.

    Проблема размытости понятия безопасности ПО, также была продемонстрирована в докладе Екатерины Рудиной из Лаборатории Касперского “Модель зрелости безопасности интернета вещей для установления, согласования и ограничения требований к операционным системам”. Из доклада следовало, что понятие безопасность может различаться в применении к разным сферам, и даже к разным типам устройств и продуктов. Что очевидно, ну зачем, например, на вашем фитнес браслете антивирус. Поэтому в Industrial Internet Consortium, в котором состоит и Лаборатория Касперского, предложили использовать модель зрелости безопасности интернета вещей (IoT Security Maturity Model, IoT SMM) для формулировки понятия безопасности для конкретного случая.

    Думаю, по причине трудной отделяемости security и safety докладов по чистой информационной безопасности было не очень много. Ярким примером такого выступления был доклад от комиттера OpenSSL Дмитрия Белявского “Гостификация ПО: подход из мира Open Source”. В котором автор рассказал, о трудностях поддержки национальных стандартов по криптографии.

    Функциональная безопасность


    Функциональная безопасность (safety software) в том или ином виде присутствовала практически во всех докладах на конференции. Ведь если посмотреть глубже, то даже в уже упомянутой дискуссии по поводу устаревания языка Си подразумевалось, что данный язык небезопасен и с его помощью очень просто “выстрелить себе в ногу”.

    Судя по докладам на конференции, улучшение функциональной безопасности (надежности) ПО участникам видится в применении инструментальных средств. Хотя, возможно, это дань заявленной теме конференции — инструменты. Поэтому подавляющее большинство докладов предлагало именно инструментальный подход. Один из организаторов конференции ИСП РАН специализируется на разработке инструментов для статического и динамического анализа кода. Собственно ИСП РАН и задал тон выступлением Александра Герасимова c докладом “Применение инструментов автоматического анализа программ в цикле разработки безопасного ПО”.

    По теме разработки статических анализаторов был доклад от Владимира Козырева из компании Advalange “Разработка инструментария сбора и анализа покрытия бортового программного обеспечения”. Представленный инструментарий был разработан для целей верификации бортового ПО по стандарту DO-178C, но этот же инструментарий может быть использован не только в бортовом ПО, ведь анализируемый код на покрытие это обычный Си.

    Кроме докладов про разработку инструментов, было несколько докладов про опыт использования подобных (или этих же) инструментов. Например, доклад Петра Девянина из РусБИТех-Астра с длинным названием “Опыт применения инструментальных средств для повышения доверия к механизмам защиты ОССН Astra Linux Special Edition” рассказывал об опыте применения этих инструментов к модулю системы безопасности для их ОС.

    Естественно, на конференции были представлены не только инструменты анализа ПО но и другие, с помощью которых можно повысить надежность ПО. Очень интересно было послушать Дмитрия Дагаева с докладом “Масштабируемые Оберон-технологии как средства обеспечения защищенного ПО критически важных систем”. Автор доклада является главным конструктором SCADA СУОК для АЭС. Поэтому не понаслышке сталкивался с системами с “повышенными требованиями в части функциональной безопасности и защиты от кибер-угроз” (цитата из аннотации к его докладу). Для увеличение безопасности ПО автор предлагает использовать Оберон технологии. Автор языка Оберон Николаус Вирт, вложил идею внесения ограничений, что существенно уменьшает риск написания небезопасного ПО. При этом с помощью доработки компилятора автор доклада, предлагает создавать образы, нацеленные на различные задачи и платформы. Доклад был мне очень близок, поскольку мы в Embox пришли к похожим идеям по ограничениям. Но предложили ограничения вносить с помощью языка описания модулей ( декларативного языка собственного сочинения нацеленного на конкретную задачу). И для генерации артефактов позволяющих создавать образы под конкретную задачу, на наш взгляд, также проще использовать отдельный язык для описания этих артефактов.

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

    Средства отладки


    На конференции были представлены несколько средств отладки и профилирования системного ПО.
    Валерий Егоров из компании НТП «Криптософт» (создатель QP ОС) рассказал об отладчике PathFinder, который используется в их гипервизоре QP VMM. Естественно, все свое, со всеми вытекающими достоинствами и недостатками.

    Денис Силаков, старший системный архитектор, Virtuozzo
    Рассказал об опыте поиска ошибок, основанном на ABRT (Automatic Bug Reporting Tool). Сборка лога всего, что может пригодиться для анализа, отправка отчета при возникновении внештатной ситуации на сервер, и дальнейший анализ уже на сервере.

    Федор Чемерев из НИИСИ РАН рассказал про средства трассировки в ОС РВ семейства “Багет”. Поскольку ОСРВ “Багет” ориентирована на встраиваемые системы, то и в случае Virtuozzo на инструментальной машине происходит сбор информации, а анализ происходит на сервере. Сбор информации происходит путем записи в журнал событий, при этом журнал может анализировать и без внештатных ситуаций.

    Модульный подход


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

    Кроме этого были еще целых три доклада, каждый из которых предлагал собственный подход к проблеме обеспечения модульности. Дмитрий Алексеев из ООО «Эремекс» представил доклад “Внедрение зависимостей в компонентно-ориентированном ПО на C/C++”. В нем автор рассказал о переключении конфигурации различных модулей ядра ОС FX-RTOS и также различных интерфейсов. Реализован проект на основе макросов. Подробнее в статье на хабре.

    Я, Антон Бондарев, как участник проекта Embox, представил доклад “Опыт разработки и применения системы сборки на основе специализированного языка программирования”, в котором рассказал о нашем опыте разработки языка Mybuild о чем частично писали на хабре. В нашем случае модульность и внедрение зависимостей обеспечивается с помощью отдельных файлов, в которых на декларативном языке описываются модули.

    И третий это доклад от Маллачиева Курбанмагомеда из ИСП РАН “Об использовании модульного подхода во встраиваемых операционных системах”. Данный инструмент был использован в еще одной ОС JetOS. Для описание модулей используется язык YAML. К сожалению, не было приведено примеров, но озвученная идея была очень интересна и мы ее обдумываем в нашем проекте. Идея заключается в том, чтобы экспортировать (декларировать) интерфейс и объекты могут подключаться именно через этот интерфейс. Была озвучена мысль, что авторы переизобрели IDL. Но это конечно не так, просто близкие идеи.

    Такое количество докладов по модульному или компонентному подходу, наверное, указывает на важность компонентной модели, для создания надежного ПО. Ведь ни у кого не возникает сомнений в том, что модульный подход может уменьшить сложность ПО, а следовательно и его надежность; что правильная структура (архитектура) ПО дает поразительные результаты; что правильный API (по сути дела контракт для ПО) делает ПО более поддерживаемым. Но легче сказать о том, что нужно сделать правильный интерфейс, чем реализовать его. Например, в докладе про Оберон предполагается использовать модули без состояния. Естественно, это решает проблему, но лично я никогда не видел реальной системы, которая не имела бы состояния.

    Возвращаясь к дискуссии об устаревшем Си


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

    Сначала приведу аргументы той части участников, которая поддержала идею. Очевидно, что идею поддержал Дмитрий Дагаев, автор доклада про Оберон. В качестве аргумента он привел фотографию где, он на снимке с Николаусом Виртом держит плакат с надписью о том, что обучать программированию нужно только на Обероне. Другие участники дискуссии выдвинули тезис, что и архитектура фон Неймана, несколько устарела, ну как минимум можно использовать тегированную память, как в архитектуре Эльбрус. Причем речь шла не об архитектуре Эльбрус, а о современных тенденциях архитектуры ARM, и сообщил об этом уже упомянутый Александр Попов. Естественно, тут же нашлись желающие написать ОС, часть функций которой будет реализована аппаратно. Еще целый ряд участников, развивая тему использования другого языка, естественно, предложили использовать функциональные языки программирования. Развивая тему языка, пришли к выводу, что, оказывается, у нас в стране нет сертифицированных средств разработки, например, компилятора под ARM, да и компиляторы, которые разрешены к использованию, могут содержать закладки. Поэтому очевидно, что сначала нужно создать компилятор, а уж потом на его основе писать ПО, в том числе и операционные системы.

    Аргументы второй части участников дискуссии, были не то чтобы в пользу использования языка Си, скорее они объясняли, почему этот язык до сих пор является стандартом для создания ядер ОС. Звучали такие аргументы. Синтаксис языка Си подразумевает полный и явный контроль программистом всего в программе, в том числе и выделения памяти, что позволяет создавать очень эффективные с точки зрения ресурсов алгоритмы. Язык Си, действительно, поддерживается средствами разработки, взять например gcc. Синтаксис языка очень простой и знаком очень большому количеству людей.

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

    Абсолютно согласен, сначала нужно развить индустрию и обучить специалистов, а это очень долгие процессы, пока же приходиться использовать кучу уже разработанного ПО на языке Си, поскольку оно гораздо надежнее и более отлаженное, чем вновь созданное, пусть и на передовых технологиях. Ведь хоть и не на данной дискуссии, но на конференции звучали подобные предостережения. Например, автор доклада о гостификации криптографического ПО Дмитрий Белявский на вопрос, что нужно знать разработчику занимающемуся безопасностью, ответил, “никогда не пишите криптографию самостоятельно”. А Дмитрий Шевцов из ФСТЭК, попросил больше заботиться о поддержке разработанного ПО.

    Про обучение специалистов, наверное, самый важный вопрос: на чем “думают“ специалисты — на том и будет разработано ПО, вполне возможно, что язык Си стал стандартом де факто для ОС, поскольку в нем были UNIX и Minix (а может, именно потому, что был задуман для разработки UNIX). Поэтому проект обучения школьников и студентов программированию на языке Оберон Информатика 21 может дать свои плоды, правда, должно пройти немало времени.

    Заключение


    Как я уже сказал во введении, данная конференция позволяет делиться идеями, обсуждать и дискутировать. По многим вопросам были представлены несколько подходов, например, про модульное ПО и безопасное ПО. Причем организаторы конференции сознательно зовут докладчиков с разными подходами и это делает конференцию еще более интересной. Ну и конечно, конференция очень открытая, как сказал Дмитрий Завалишин в ходе дискуссии об языке Си, “Пять минут славы каждому“.

    P.S.


    Только что прочитал статью на хабре под названием “ Технические СМИ как базар”. В ней объясняется, как важно иметь несколько различных мнений. Предлагаю продолжить дискуссию о языке Си на Хабре. Например, очень интересно узнать, есть ли кросс-платформенные промышленные решения на rust или go?
    Embox
    161,73
    Открытая и свободная ОС для встроенных систем
    Поделиться публикацией

    Похожие публикации

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

      +5
      Основная проблема Си есть его же преимущество:
      синтаксис языка Си подразумевает полный и явный контроль программистом всего в программе

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

      Согласен отчасти, много софта есть которое временем проверено. Но возьмем HAL для Stm, сколько люди его пользуют? А баги приводящие к отказу где-нить на трубопроводе на каком-нибудь автомате до сих пор люди ловят, да что там HAL, заголовочники на Си для микроконтроллеров, написанные производителем содержат ошибки (например по выравниванию структур). Конечно есть много сертифицированных Сишных библиотек к ним доверия больше, но бывают случаи даже SIL3 операционки выдают такие фокусы из-за макроса… Правда надо сказать, что большинство таких сертификатов получается за «Проверенно временем»
      GCC кстати не рекомендован для использования при разработке надежного софта.
        0
        Основная проблема Си есть его же преимущество

        Абсолютно согласен! Но подразумевается что при написании ядра ОС, ну внимательнее разработчики должны что ли быть :) А взять например язык более высокого уровня, кто сказал что разработчики компилятора или рантайма (виртуальной машины) не сделают ошибку?

        Но возьмем HAL для Stm, сколько люди его пользуют? А баги приводящие к отказу где-нить на трубопроводе на каком-нибудь автомате до сих пор люди ловят, да что там HAL, заголовочники на Си для микроконтроллеров, написанные производителем содержат ошибки (например по выравниванию структур)

        На мой взгляд HAL для stm ок относительно свежий, врядли можно сравнивать с Unix или теми же Виндами, там проверка временем и количеством использования сильно больше!

        Правда надо сказать, что большинство таких сертификатов получается за «Проверенно временем»

        Так может это и есть правильный подход? :)
          +1
          GCC кстати не рекомендован для использования при разработке надежного софта.

          А что рекомендуют и обычно используют?

            0

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

              0
              GreenHills, IAR 8.22 только тот, что с сертификатом.
                0
                Мне казалось, что у GHS нет сертификата для 50128. Впрочем у них достаточно других сертификатов.

                UPD: Да, где были мои глаза — есть!
              0
              GreenHills, и IAR 8.22.3 только тот, что с сертификатом.
              0

              Вот тут я не понял. Как смена языка (с Си на Раст например) спасет вас от грубых ошибок производителя в msp/bsp?

                0
                Если производитель, например, будет заголовочники предоставлять не на Си, а на С++, то можно избежать всякой ерунды…
                Ну вот пример, STM предоставила flashloader для IAR… Если что файл лежит тут для IAR 8.20
                EmbeddedWorkbench8.1\arm\src\flashloader\ST\FlashSTM32F4xx\inc:
                Заголовок спойлера
                typedef struct
                {
                  __IO uint16_t SR;         /*!< USART Status register,  Address offset: 0x00 */
                  uint16_t      RESERVED0;  /*!< Reserved, 0x02                     */
                  __IO uint16_t DR;         /*!< USART Data register,  Address offset: 0x04 */
                  uint16_t      RESERVED1;  /*!< Reserved, 0x06              */
                  __IO uint16_t BRR;        /*!< USART Baud rate register,  Address offset: 0x08 */
                  uint16_t      RESERVED2;  /*!< Reserved, 0x0A                                                */
                  __IO uint16_t CR1;        /*!< USART Control register 1,  Address offset: 0x0C */
                  uint16_t      RESERVED3;  /*!< Reserved, 0x0E                                                */
                  __IO uint16_t CR2;        /*!< USART Control register 2,  Address offset: 0x10 */
                  uint16_t      RESERVED4;  /*!< Reserved, 0x12                                                */
                  __IO uint16_t CR3;        /*!< USART Control register 3,  Address offset: 0x14 */
                  uint16_t      RESERVED5;  /*!< Reserved, 0x16                                                */
                  __IO uint16_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */
                  uint16_t      RESERVED6;  /*!< Reserved, 0x1A                            */
                } USART_TypeDef;


                Как вы думаете, что тут произошло? Правильно, в некоторых случаях тут были дырки по 2 байта между элементами в 2 байта, потому что выравнивание по 4 байта на 32 битной машине. В итоге даже не представляю как flashloader работает через UART :)
                А если бы использовали С++, могли бы написать, что-то типа этого
                Заголовок спойлера
                struct Uart
                {
                  __IO uint16_t SR;         /*!< USART Status register,                   Address offset: 0x00 */
                  uint16_t      RESERVED0;  /*!< Reserved, 0x02                                                */
                  __IO uint16_t DR;         /*!< USART Data register,                     Address offset: 0x04 */
                  uint16_t      RESERVED1;  /*!< Reserved, 0x06                                                */
                  __IO uint16_t BRR;        /*!< USART Baud rate register,                Address offset: 0x08 */
                  uint16_t      RESERVED2;  /*!< Reserved, 0x0A                                                */
                  __IO uint16_t CR1;        /*!< USART Control register 1,                Address offset: 0x0C */
                  uint16_t      RESERVED3;  /*!< Reserved, 0x0E                                                */
                  __IO uint16_t CR2;        /*!< USART Control register 2,                Address offset: 0x10 */
                  uint16_t      RESERVED4;  /*!< Reserved, 0x12                                                */
                  __IO uint16_t CR3;        /*!< USART Control register 3,                Address offset: 0x14 */
                  uint16_t      RESERVED5;  /*!< Reserved, 0x16                                                */
                  __IO uint16_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */
                  uint16_t      RESERVED6;  /*!< Reserved, 0x1A  */ 
                  static_assert(sizeof(Uart) == sizeof(uint16_t) * 14);
                } ;
                


                И тогда бы эта ошибка была бы выявлена на этапе компиляции через static_assert. Хотя наверное и на Си могли бы через #if? Но видимо, там думать надо было бы :), а тут нормально все стандартами языка можно сразу проверить…
                  +1
                  На чистом Си тоже есть static_assert прямой в стандарте (_Static_assert). Для выравнивания есть оператор offsetof, правда нет нормальной стандартной реализации, но огромное количество компиляторов поддерживают его с помощью builtin.
                    0

                    Ага, видимо заголовочники писались до С11 стандарта

                      0
                      А в C99 можно получить тот же эффект с помощью умело написанного enum.
                      0

                      Хм, а что за случаи такие хитрые? Вроде бы тут выравнивания не должно появиться…
                      Или его макрос __IO добавляет?

                        0
                        Общий случай, выравнивание по 4 байта, идет 16 битный инт, потом дырка в 2 байта, потом 16 битный инт RESERVED, потом дырка в 2 байта. И компилятор имеет на это полное право, он же не обязан за вас додумывать, что вы хотите два 16 битных инта запихать в одну ячейку памяти 32 битную и в итоге сделает размер этой структуры в 2 раза больше ожидаемого и адреса регистров не те, что ожидает программист. Компиляторы конечно не такие тупые, чтобы дырки всавлять, но в общем случае они должны это сделать исходя из архитектуры микропроцессора. Любой статический анализатор кода руганется жестко с сообщение уровня Ошибка.
                        _IO это volatile.
                          +1
                          Ну право-то он имеет, согласен (чтобы не имел, нужен __attribute__(packed)). Но обычно компиляторы выравнивают поля структур на их размер, то есть char'ы выравниваются побайтно, int16 на 2 байта, int32 — на 4 байта. То есть могут быть дырки в промежутках между char и int16 или int16 и int32, но не между полями одинакового размера (если их, конечно, не выравнивают специально каким-то нестандартным образом через соответствующий атрибут).
                            0
                            Да это скорее всего так для IAR, но точно ли это будет так для другого компилятора?
                            Some Arm cores require that when accessing data in memory, the data must be aligned.
                            Each element in a structure must be aligned according to its specified type requirements.
                            This means that the compiler might need to insert pad bytes to keep the alignment correct.
                              0

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

                            0
                            А что, адреса 16-битных регистров ввода-вывода выровнены по границам 2 байт?
                              0
                              Как же они 16 битные, когда архитектура 32 бита. Они 32 битные, просто старшие 16 бит не используются…
                              image
                                0
                                И какой же вывод? Каковы адрес и смещение относительно базы рассматриваемого 16-битного регистра? Каковы адрес и смещение относительно базы следующего поля? Не на тот ли самый слоп больше?
                                  0
                                  вывод такой, мы не можем гарантировать, что компилятор сделает то, что мы задумали и не вставит дырки, и поэтому такую структуру без выравнивания использовать нельзя… и надо бы её переделать для данного микроконтроллера вот в такую:
                                  struct Uart
                                  {
                                    __IO uint32_t SR;         
                                    __IO uint32_t DR;         
                                  .
                                  .
                                  .
                                  }
                                  
                                    0
                                    Лучше явно указать компилятору необходимость упаковки структуры с помощью соответствующей прагмы или атрибута. Ваш вариант тоже ничего не гарантирует в общем случае, компилятор все еще волен делать любые padding'и, только уже между int32-полями :) На самом деле это обязательно нужно делать при написании переносимого кода, для работы которого важны смещения внутри структур, но если код де-факто не будет переносимым (предполагается работа на конкретной архитектуре и сборка конкретным компилятором), то этим часто пренебрегают.
                                      0
                                      Нет для 32 битной машины выравнивание по умолчанию 4. считайте стоит pragma(4). Прагма непереносимый код, поэтому не надо её использовать. А гарантировать можно с помощью static_assert. Если вдруг этот код будете запускать на 64 битной машине, он вывалится с ошибкой… Но если уж вы хотите переносить на все типы машин, то тогда нужно делать, что-то типа этого:
                                      template <unsigned int sz>
                                      struct Register_traits { };
                                      
                                      template <>
                                      struct RegisterTraits<8>  { using internal_type = std::uint8_t; };
                                      
                                      template <>
                                      struct RegisterTraits<16> { using internal_type = std::uint16_t };
                                      
                                      template <>
                                      struct RegisterTraits<32> { using internal_type = std::uint32_t; };
                                      
                                      template <>
                                      struct RegisterTraits<64> { using internal_type = std::uint64_t; };
                                      //Где-нибудь в отдельном h файле, для конкретной 32 битной машины или через #ifdefine определить тип так: 
                                      using tRegisterType = RegisterTraits<32> 
                                      //А потом так вот юзать...
                                      struct Uart
                                      {
                                        __IO tRegisterType SR;         
                                        __IO tRegisterType DR;         
                                      .
                                      .
                                      .
                                      }
                                      static_assert(sizeof(Uart) == sizeof(tRegisterType) * 14);
                                      

                                      Но если совсем нет доверия, то лучше тогда вообще такие структуры не использовать и напрямую с адресами регистров работать типа такого:
                                      Register<32, readOnly> Usart1Sr   { 0x40021000 };
                                      Usart1Sr = 2; // ошибка компиляции, регистр только для чтения
                                      uint32_t value = static_cast<uint32_t>(Usart1Sr) ; //Ок, 
                                      

                                      Вот тут можно почитать
                                        0
                                        Нет для 32 битной машины выравнивание по умолчанию 4

                                        Ну если что-то такое считается «по умолчанию», то код по определению непереносимый :) Типа рассчитан на нормальную работу только на 32-битной архитектуре.

                                        Прагма непереносимый код, поэтому не надо её использовать.

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


                                          Что, внезапно, еще более общО и переносимо.
                                        0
                                        Гарантировать нечего: компилятор не вставит дырки только если это указано в его настройках или параметрах вызова. Покажите пример, где эту структуру размещают в памяти. И пример, где наличие слопа приводит к проблемам, но в реально работающим коде, а не в выдуманном…
                                          0
                                          Я не могу привести код, потому что текущий IAR такого не позволяет, но это не означает, что его нет… сам же IAR пишет:
                                          All data types must have a size that is a multiple of their alignment. Otherwise, only the first element of an array would be guaranteed to be placed in accordance with the alignment requirements.
                                          Every C data object has an alignment that controls how the object can be stored in memory. Should an object have an alignment of, for example, 4, it must be stored on an address that is divisible by 4.

                                          The reason for the concept of alignment is that some processors have hardware limitations for how the memory can be accessed.
                                          Assume that a processor can read 4 bytes of memory using one instruction, but only when the memory read is placed on an address divisible by 4. Then, 4-byte objects, such as long integers, will have alignment 4.
                                          A structure type will have the same alignment as the structure member with the most strict alignment.
                                          Кстати не зря же в поздних версиях CMSIS эти заголовочники поправили…
                                          Новые заголовочники
                                          typedef struct
                                          {
                                            __IO uint32_t SR;         /*!< USART Status register,                   Address offset: 0x00 */
                                            __IO uint32_t DR;         /*!< USART Data register,                     Address offset: 0x04 */
                                            __IO uint32_t BRR;        /*!< USART Baud rate register,                Address offset: 0x08 */
                                            __IO uint32_t CR1;        /*!< USART Control register 1,                Address offset: 0x0C */
                                            __IO uint32_t CR2;        /*!< USART Control register 2,                Address offset: 0x10 */
                                            __IO uint32_t CR3;        /*!< USART Control register 3,                Address offset: 0x14 */
                                            __IO uint32_t GTPR;       /*!< USART Guard time and prescaler register, Address offset: 0x18 */
                                          } USART_TypeDef;

                                            0
                                            Представленные структуры в плане смещения от начала структуры значимых полей идентичны. Вы пишете в регистр UART 16-битное значение или 32-битное? Каковы требования к выравниванию 16-битного целого на 32-битном ARM CortexM? Каков адрес следующего поля структуры типа short при выравнивании по умолчанию на этой платформе? Вы уверены, что проверка static_assert(sizeof(Uart) == sizeof(uint16_t) * 14); не выполнится?
                                            Вроде бы 16-битные поля в данном случае будут выровнены по четной границе, не по 4 байтам, если это не особенность IAR.
                                            Из врожденной скромности IAR по рукой не имеется, но и gcc-none-arm-eabi и armcc говорят, что все нормально.
                                            Соглашусь, что добиваться верного выравнивания с помощью явных полей анахронизм, но допустимо. Я бы сделал __attribute__((aligned(4))) добавил, чтобы стало так, как Вы хотите, но можно было бы пользоваться uint16_t без приведения типа.
                                              0
                                              Может проще объявлять все регистры 32-битными, каковыми они и являются? Всегда лучше быть честным, чем умным.

                                              Впрочем и это не снимает полностью вопрос переносимости.
                                                0
                                                А они, регистры, 32-битные? На железе?
                                                Адреса MMIO регистров 32-битные, а регистры на железе могут быть и 8-, и 16-, и 32-, и, подозреваю, даже 64-битными. В языке C, а вслед за ним в C++ это явно не выражается, по крайней мере пока: ISO/IEC TR 18037 висит непринятым, хотя нужен не только во встроенных системах.
                                                Вот и получается разной степени костыльные решения для того, чтобы сделать адреса 16-битных регистров правильно расположенными относительно базового адреса в ситуации, когда адреса регистра должны начинаться по границе 4 байт, а выравнивание 16-битного поля структуры по умолчанию — 2 байта. Или все прятать за кучей неприглядных макросов/инлайн-функций. Или как-то совмещать эти методы.
                                                Что до переносимости, то сила C именно в том, что можно сделать непереносимые решения, там и когда это нужно. Чем ближе к железу, тем меньше переносимости и больше трюков, расширений компилятора и т.д.
                                                В силу изложенного не могу сказать, что решение инженетов STMicro чем-то хуже или лучше, чем обмазывания 4-х записей в регистры кучей std::enable_if.
                                                  0
                                                  А они, регистры, 32-битные? На железе?


                                                  Могу ошибаться, но по-моему конкретно эти регистры 32-битные заложены в железе (а не просто отображены как 32-битные), по крайней мере обратное не указано явно.

                                                  регистры на железе могут быть и 8-, и 16-, и 32-, и, подозреваю, даже 64-битными


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

                                                  ISO/IEC TR 18037


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

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


                                                  И это адище какое-то. Если вдруг вам понадобится 8-битный регистр среди кучи других регистров, то потребуется за ним гуськом расположить три таких же поля… И строго, очень строго следить за тем, чтобы кто-нибудь где-то в топе модуля не вписал pragma pack (2) например.

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

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


                                                  С этим не спорю.
                                                    0
                                                    И это адище какое-то.

                                                    Добро пожаловать в реальный мир низкоуровневого программирования)))
                                                      0
                                                      Добро пожаловать в реальный мир низкоуровневого программирования)))


                                                      Вы так говорите, будто я не живу в этом мире с самого института ))
                                                      0
                                                      Могу ошибаться, но по-моему конкретно эти регистры 32-битные заложены в железе (а не просто отображены как 32-битные), по крайней мере обратное не указано явно.

                                                      Тоже могу ошибаться, но на железе они вроде бы могут быть 16-битными, а могут быть и 32-битными. В конкретной аппаратной реализации они 16-битные, поэтому старшее слово в 32-битных (с точки зрения memory map) регистрах зарезервировано. Адреса этих регистров да, будут кратны 4 байтам. И если убрать тот или иной способ указать реальное выравнивание 16-битных uint16_t volatile xx, то будет запись/чтение зарезервированной части регистра с понятными последствиями. На сегодняшний день я не знаю красивого и эффективного решения подобных проблем.
                                                        0
                                                        В конкретной аппаратной реализации они 16-битные, поэтому старшее слово в 32-битных (с точки зрения memory map) регистрах зарезервировано


                                                        Простите, а вы это знаете, или предполагаете?

                                                        Простой пример из практики: CPLD-сателлит у процессора, внутри нее есть набор 32-битных регистров, у большинства из которых доступна для использования только младшая половина, остальное зарезервировано (физически туда писать можно, ничего страшного не произойдет, просто смысла нет). В документации, как и полагается, старшее слово обозначено как reserved, однако регистр от этого 16-битным не становится. Конечно в микроконтроллере ситуация чуть иная, и скорее всего неиспользуемые регистры (которые будут только место занимать) физически отсутствуют, однако это не мешает адресным дешифраторам прикидываться валенком.

                                                        И если убрать тот или иной способ указать реальное выравнивание 16-битных uint16_t volatile xx, то будет запись/чтение зарезервированной части регистра с понятными последствиями. На сегодняшний день я не знаю красивого и эффективного решения подобных проблем.


                                                        Если мы используем структуру для доступа к регистрам — то да, суровое танго.
                                                          0
                                                          Простите, а вы это знаете, или предполагаете?

                                                          Как там конкретно в железе даже не задумывался. Я знаю, что «работает» только изменение младших 16 бит по адресу 32-битного целого и что если объявить этот адрес адресом 16-битного целого — то это будет работать.
                                                          А вот можно ли без неприятных последствий записать по этому адресу 32-битное целое с мусором в старшем слове — не проверял. И не очень-то хочется.
                                            0
                                            Вот именно! То есть проблема уже на уровне описания регистров, буквально в голове у писавшего.
                                  0
                                  Какое там выравнивание? Адрес структуры напрямую прописан, его можно принять и передать — но не изменить.
                                    0

                                    Выравнивание по полям структуры 16 битный int выравнивается на 4 байта, ячейки памяти то 32 битные, на не 16.

                                      –2
                                      Ну не может uint16_t в структуре с фиксированным адресом внезапно занять 4 байта, typedef мешает.
                                      А вот в новой структуре созданной например так:
                                      USART_TypeDef new_usart;
                                      размер переменных может быть увеличен в угоду ускорения общего алгоритма. Но для этого ещё постараться надо.
                                        0
                                        Просто чтобы не лезть в дебри, читаем документацию на компилятор:
                                        Some Arm cores require that when accessing data in memory, the data must be aligned.
                                        Each element in a structure must be aligned according to its specified type requirements.
                                        This means that the compiler might need to insert pad bytes to keep the alignment
                                        correct.
                                        There are situations when this can be a problem:
                                        ● There are external demands; for example, network communication protocols are
                                        usually specified in terms of data types with no padding in between
                                        Efficient coding for embedded applications
                                        ● You need to save data memory.
                                        Use the #pragma pack directive or the __packed data type attribute for a tighter
                                        layout of the structure. The drawback is that each access to an unaligned element in the structure will use more code.
                                        Alternatively, write your own customized functions for packing and unpacking
                                        structures. This is a more portable way, which will not produce any more code apart
                                        from your functions. The drawback is the need for two views on the structure data—
                                        packed and unpacked.
                                          –1
                                          Просто чтобы не лезть в дебри

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

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

                                              –1
                                              Очевидно что получится фигня, ещё до копирования — в момент заполнения структуры. Компилятор не может оптимизировать живые переменные в стеке, и будет методично лохматить содержимое фарша до полной готовности. То-есть получится очень много лишнего кода.
                                              Ну и есно копирование через memcpy может сбоить.
                                              Кроме бага с выравниванием, есть ещё один редко уловимый глюк — когда периферия неадекватно реагирует на слишком быструю запись. Не вся и не везде, но есть.

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

                                                Забыли пока про регистры, обе структуры находятся в обычной памяти, просто одна из них — по фиксированному адресу. Как должна работать memcpy в этой ситуации?

                                                  0
                                                  Уже ответил выше — возможно будет сбой.
                                                  Потому что для корректной работы memcpy — структура должна иметь объединение с массивом. Там и разрядность данных, и количество элементов — всё это будет известно ещё на этапе компиляции. Что сократит количество ошибок пользователя до нуля.
                                                    0

                                                    Хорошо, а вот так?


                                                    struct foo fixed_addr_var;
                                                    struct foo auto_addr_var;
                                                    
                                                    foo *p1 = &fixed_addr_var, *p2 = &auto_addr_var;
                                                    *p1 = *p2;

                                                    Вот так будет ошибка или нет?

                                    0
                                    А там нигде в начале файла нет: #pragma pack(1)?
                                    Который просто на весь файл распространяется.
                                      0
                                      Посмотрел, нету…
                                        0
                                        То же самое предположил. Иначе как оно работает? Разве что на самом деле потом никак не используется…
                                        0
                                        Ну стоп, а в чем проблема-то? Ну оказались поля на самом деле по четыре байта, а не по два, кому от этого плохо? Аааа, кажется я догадываюсь… Наверное кто-то потом решил, что эта структура в памяти расположена сплошняком без промежутков между полями, и значит можно с ней работать как с массивом? Ну так ССЗБ, не?

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

                                          Судя по volatile-полям, один из экземпляров этой структуры располагается в памяти по фиксированному адресу, и должен этими самыми volatile-полями накрывать отображенные в память порты ввода-вывода.

                                            0
                                            Да, я понял, про то и пишу — воспринимать эту структуру как линейный массив (чего угодно, в том числе регистров) в общем случае нельзя. И хотя это очень распространенный прием (и от него трудно убежать — например я из-за лени использую STM HAL и пожинаю сопутствующие плоды), но мне он очень не нравится, поскольку опускает нас с уровня языка на уровень понимания его трансляции. Отсюда все эти сакральные знания про gcc aligned и ему подобное.

                                            Добавлю, что дело не только в необходимости держать в голове выравнивание, нужно еще как-то защититься от случайных ошибок вида «вставили поле, не подумав про смещения». Я это встречал, и после такого вся красота использования структур для отображения регистров теряется.
                                              0
                                              В анализе и высказываниях по поводу этой структуры неплохо учитывать реальные требования к выравниванию полей структур и адресов MMIO.
                                                0
                                                В анализе и высказываниях по поводу этой структуры неплохо учитывать реальные требования к выравниванию полей структур и адресов MMIO


                                                Не неплохо, а необходимо. Либо можно просто отказаться от использования структур для доступа к группам регистров (но здесь есть свои минусы).
                                    +2
                                    Коллеги показали работу не только на отечественных Эльбрусе и Байкале, но и, например, на такой относительно редкой архитектуре как RISC-V.
                                    RISC-V — не «относительно редкая» архитектура, а «самая быстрорастущая». Ей только в России уже не меньше трех компаний занимается, а в мире так и вовсе уже счет за сотню дизайнов ушел, включая таких монстров, как Nvidia и Western Digital.

                                      0
                                      Все таки относительно редкой, поскольку довольно новая.
                                      Безусловно перспективная, согласен самая быстрорастущая, но посмотрите например сколько дистрибутивов Linux поддерживает ARM и MIPS, а сколько RISC-V? До недавнего времени, это было скорее встроенное решение на основе ядер ПЛИС.
                                      +5
                                      Вопрос про использование Rust вместо Си уже отчётливо задают в разных проектах разработки ОС, компиляторов и аппаратных средсв.

                                      Вот например, цитата из FAQ проекта Keystone-enclave – открытого каркаса TEE (Trusted Execution Environments) для процессоров и микроконтроллеров с системой команд RISC-V:

                                      Q: Why are enclaves/SM/etc written in C? Why not Rust (or another modern language)?
                                      A: Rust RV64 support was unavailable when Keystone was started. Few options for the security monitor besides C were available. We are keeping a close eye on Rust support as it matures for RV64, and expect to support it for enclaves at a minimum.
                                        +1
                                        Абсолютно согласен. Rust очень интересен, и мы в Embox на него тоже облизываемся, но пока речь идет о пробе пера, каком нибудь модуле на Rust.

                                        Он безусловно растет, но я лично о нем уже лет 5 назад слышал. И задавали все тот же вопрос, почему не на rust? Он такой хороший надежный, решает много очевидных проблем Си. Но когда речь заходила, а почему сами не используете, тут же «у нас продакшен мы не может экспериментировать». :)
                                          0

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

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

                                              Я конкретно про embedded. Пока кроме проектов Japaric и ведомой им embedded working group не видно ничего. Думаю, если сравнить с тем, сколько вкладывается в поддержку С в тулчейнах, разница будет порядка на 3. Если не больше.

                                                0
                                                В смысле никого? www.tockos.org
                                                  +1

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

                                                  0
                                                  Думаю, если сравнить с тем, сколько вкладывается в поддержку С в тулчейнах, разница будет порядка на 3. Если не больше.

                                                  Думаю сильно больше. Но не стоит забывать, что коммерческие компании должны еще и прибыль генерить, в Си огромная готовая инфраструктура, в которую ты вкладываешь и используешь кучу готового. В Rust пока такого нет, точнее это не сопоставимо по объемам. Поэтому пока в основном на уровне исследований вложения идут. Взять производителей микроконтроллеров, они взяли выпустили чип со стандартной архитектурой (могут не вкладываться в компилятор), написали драйвера для переферии и все можно выпускать, есть уже куча rtos, ide, средств разработки, библиотк, и т.д. Разработчикам готовых устройст это выгодно, вышел дешевый чип, и можно сразу начинать производство железки, ведь и программисты готовые есть.
                                                    0

                                                    Я об этом и говорю. Требуется преодолеть гигантскую инерцию.

                                            +1

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

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

                                              А можно пару примеров, что в синтаксическом новоязе Rust так сильно причиняет боль?
                                                –1
                                                вечная американская боль

                                                Всякие си с плюсами и даже корпоративной джавой уживаются как-то, хотя я не эксперт в этих вопросах


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

                                                Все перечислять не буду, можно на примере самых основных. Для обозначения переменной нужно два ключевых слова let mut, аналогично его должны иметь модифицируемые параметры функций. Примитивы все имеют явную разрядность, которую приходится держать в голове (неявного каста тут нет), даже если это не нужно. Функции надо помечать ключевым словом, при этом все равно явно задавая возвращаемый тип. Каждый match (здешний switch) должен обрабатывать все возможные области значений, необходимо таскать с собой пустую строку дефолта _ => {}. При создании лямбд у разработчиков сломались клавиши скобок: let closure = |i: i32| -> i32 { i + 1 };. Возвращение значений из функций может быть явным и не- (просто последнее выражение без ;), но выражения уже не умеют в return. Из-за этого, кстати, код труднее не писать, но читать — без цветной пометки эти строчки на раз пропускаются, либо вводят в смущение. И, да, выражения теперь возвращают значения, поэтому в чужом коде можно ожидать конструкций из серии:


                                                // "умная" инициализация
                                                let mut x = if a {
                                                    // сотня строк кода
                                                    0
                                                } else if b {
                                                    // снова куча логики
                                                    5
                                                } else {
                                                    // еще две сотни
                                                    1
                                                }
                                                ...
                                                match x {
                                                    // и фиг его знает, на самом деле, куда он тут попадет
                                                }

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

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

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

                                                      0

                                                      Потому что портить язык вредными конструкциями только чтобы сделать его более знакомым тем, кто по этим граблям походил — плохое занятие. http://www.informit.com/articles/article.aspx?p=2425867 здесь неплохо раскзаано, почему и неявные касты плохо, и тип впереди функции, и многое-многое другое.

                                                        –1

                                                        Ох уж эти глупые доктора наук Ритчи и Керниган, а потом еще и Страуструпы всякие, нагородили таких вредные конструкций, что до сих пор разгребаем, но не разгребем


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

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

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

                                                          А что, было бы плохо?

                                                    +3
                                                    Все перечислять не буду, можно на примере самых основных. Для обозначения переменной нужно два ключевых слова let mut,

                                                    Неправда, достаточно let


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

                                                    Да, помнить, что int на этой машине 2 байта, а на этой 4 намного удобнее. Или внезапно из сишки типа int32_t пропали.


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

                                                    Какие альтернативы предлагает? Очень надеюсь, не писать тип функции впереди?


                                                    Каждый match (здешний switch) должен обрабатывать все возможные области значений, необходимо таскать с собой пустую строку дефолта _ => {}.

                                                    Действительно, какая глупость.


                                                    При создании лямбд у разработчиков сломались клавиши скобок: let closure = |i: i32| -> i32 { i + 1 };.

                                                    let closure  = |i| i + 1;

                                                    Возвращение значений из функций может быть явным и не- (просто последнее выражение без ;), но выражения уже не умеют в return.

                                                    Вопрос привычки


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

                                                    Ваша претензия по сути в том, что тут "не как в си". И слава богу.

                                                      0
                                                      Неправда, достаточно let

                                                      Это будет не переменная, потому что ее нельзя будет переменить)


                                                      Или внезапно из сишки типа int32_t пропали.

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


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

                                                        0
                                                        Это будет не переменная, потому что ее нельзя будет переменить)

                                                        Её и не надо менять в общем случае.


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

                                                        Так он генерирует как раз зависимый код.


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

                                                        Упростили парсер себе таким образом. В чем проблема-то?

                                                          0
                                                          Её и не надо менять в общем случае.

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


                                                          Так он генерирует как раз зависимый код.

                                                          Неправильно выразился, сам код при написании будет меньше зависеть от платформы: какого бы размера int не был, он всегда будет целочисленным и знаковым, знания чего нам часто вполне достаточно

                                                            0
                                                            Это звучит очень странно, учитывая, что свойство буквально содержится в корне слова

                                                            Это не переменные, это — биндинги. В большинстве случаев переменные не нужны. Поэтому и let mut, чтобы ленивые люди предпочитали не использовать мутабельность там, где она не нужна.


                                                            К слову, в Rust вплоне можно перекрывать старое значение с тем же именем: let x = x + 1. Кроме того время жизни биндингов ограничено блоками, где они объявлены. И это тоже позволяет часто обходиться без мутабельности.

                                                              –3

                                                              Ну так и я о том же говорю. Но на практике выражается в многословность

                                                                0

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

                                                      +5
                                                      Для обозначения переменной нужно два ключевых слова let mut,

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


                                                      аналогично его должны иметь модифицируемые параметры функций.

                                                      Это такой же байндинг. Было бы лучше иметь несколько разных правил?


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

                                                      Единственное, что может быть немного неудобно — отсутствие неяного апкаста к более ёмкого типа. Хотя — вам не хватает неявного апкаста bool->int и неявного подсчёта хеша так, как вы не ожидали? Да, эта проблема встретилась мне в С++. Но ноги растут из С. По поводу явной разрядности — вы никогда не портировали программу с win16 на win32? С резким разрастанием размера int?


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

                                                      default int сами же авторы С посчитали очень плохой идеей. unit return же указывать необязательно. Про явное ключевое слово fn — вы соскучились по most vexing parse rule? Я — нет.


                                                      Каждый match (здешний switch) должен обрабатывать все возможные области значений, необходимо таскать с собой пустую строку дефолта _ => {}.

                                                      И это прекрасно, я считаю.


                                                      При создании лямбд у разработчиков сломались клавиши скобок: let closure = |i: i32| -> i32 { i + 1 };.

                                                      Здесь уже вкусовщина. Мне такой синтаксис кажется вполне имеющим право на жизнь.


                                                      Возвращение значений из функций может быть явным и не- (просто последнее выражение без ;),

                                                      Expression-based language. Особенность, которую надо знать.


                                                      но выражения уже не умеют в return.

                                                      Вы вполне можете использовать блок как часть выражения. И делать из него return.


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

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


                                                      В целом же, как человеку, пишущему на С++, мне ваши претензии кажутся сводящимися к "Этот язык не похож на привычный мне С". То, что множество языков скопировало этот синтаксис, не означает, что он лучший. Просто он более распространённый и привычный.

                                                        0
                                                        ваши претензии кажутся сводящимися к "Этот язык не похож на привычный мне С"

                                                        Да ну я это не скрываю, первый же комментарий содержит аналогичную подстроку:


                                                        И вечное желание сделать его максимально не С-подобным не помогает(
                                                    0

                                                    Тоже хотел уточнить, что не так? Обычный МЛ-подобный синтаксис. Собственно из синтаксиса в си нормальные только скобочки, все остальное фигово — объявление функциональных аргументов, type first, вот это все.

                                                      0

                                                      Попробуйте осилить синтаксис Nim — Rust после него покажется прогулкой в лесу под пение птиц :)

                                                    +4

                                                    Аргумент про управление памятью — практически главный. Второй — это фиксированное ABI, с которым можно быть совместимым. (Для сравнения, с C++ ABI можно быть совместимым только при компиляторе той же версии, и удачном положении луны на небе).


                                                    Однако, никто не упомянул слово Rust, который:
                                                    а) Умеет ручное управление памятью и может генерировать код без рантайма (читай, эмбедд и ОС)
                                                    б) умеет быть совместимым в обе стороны с С-ABI.


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

                                                      0
                                                      И мне странно, потому что с точки зрения безопасности, разница между С и Rust, как между ездой на крыше синкансена и в его салоне.

                                                      наверное соглашусь, хотя сам Rust не использовал.

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


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

                                                        Ох, вы открываете гигантский топик.


                                                        Совместимость с С-ABI означает, что на Rust можно написать so'шку (с которой потом может слинковаться бинарь на том же Rust). Rust как и C++ не имеет стабильного ABI, так что использование foreign interface (aka C-FFI) отличное решение.


                                                        На самом деле, никто не уверен, что на Rust можно написать конкурентную ОС общего назначения. В силу более строгой типизации Rust, не всё, что может быть написано на Си, может быть написано на Rust. В этот список в основном попадают плохие вещи (undefined behaviour), но под общую гребёнку попадают и потенциально полезные (конкурентное изменение общего состояния). Удастся ли из оставшегося сделать ОС — вопрос открытый.


                                                        ЗЫ В Раст есть unsafe (ключевое слово), которое отключает несколько важных проверок, так что наделать багов Си-уровня можно и в Rust. Другое дело, что в нормальной программе unsafe секции маленькие, а в С — начинаются с первого #include и заканчиваются EOF в конце.


                                                        А вот почему Rust'овое управление памятью чертовски безопасное (более безопасное, чем даже в языках с garbage collector'ом), быстро не описать. Это как раз его фирменная фишка — lifetimes, ownership/borrow, и, опять же, безумно строгая типизация уровня haskell.

                                                          +2
                                                          В Раст есть unsafe (ключевое слово), которое отключает несколько важных проверок, так что наделать багов Си-уровня можно и в Rust.

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

                                                            Вообще нет. unsafe так же даёт возможность работы с глобальными статическими переменными, реализовать unsafe impl (Sync). Так что им можно натворить кровавых вещей очень просто. И такие баги уже находили, хотя они жили в стд несколько лет, «проверенные временем».

                                                              +1
                                                              В целом, я с вами согласен, но я бы не назвал приведенные вами примеры как «очень просто», это я как раз отношу к категории «специально поставить перед собой такую задачу».
                                                              Изменяемые статические переменные — это вообще антипаттерн, если уж так хочется, стоит хорошо подумать, действительно ли оно вам надо, и если надо, то может быть стоит воспользоваться безопасными решениями? Тот же lazy_static + Mutex или RwLock. И unsafe не нужен и безопасный конкурентный доступ.
                                                                0

                                                                Адресная арифметика тоже подпадает под unsafe. Каст нетолстых указателей (например, для реализации си-подобного наследования) туда же.

                                                                  0

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

                                                                    0

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

                                                                      0

                                                                      Я спрашивал не про наследование вообще, а про си-подобное наследование.

                                                                        0

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

                                                                          0

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


                                                                          struct Bar {
                                                                              super: Foo,
                                                                          }
                                                                          
                                                                          impl Bar {
                                                                              fn baz(&self) { self.super.baz() }
                                                                          }

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

                                                                            0

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

                                                                              0

                                                                              Это какой-то не тот RFC. Правильное решение тут — реализация чего-то вроде derive для произвольных трейтов.


                                                                              Пока же можно какой-нибудь Into вместо наследования использовать.

                                                                                0

                                                                                Derive уже есть очень давно, но это точечное решение, которое надо руками подгонять под каждый отдельный типаж. Красиво такая штука реализована в Go — вложенные структуры без имен переносят сигнатуры своих публичных методов на внешнюю структуру. Этакий декоратор на стероидах. Rust такое наверное не светит — очень уж неявно.


                                                                                Заменить наследование для задач именно наследования, а не подстановки — нечем. Существующие решения подразумевают копипаст, что не лезет ни в какие ворота. Можно бы исхитриться и реализовывать базовый типаж для реализаций типажа-наследника, чтоб не копипастить, но увы, orphan rules прилетают и бьют по попе. Да и специализация до ума не доведена.

                                                                      0
                                                                      А как без нее решать низкоуровневые задачи? Вот прекрасная статья на тему: www.cs.kent.ac.uk/people/staff/srk21/research/papers/kell17some-preprint.pdf
                                                              0
                                                              Ох, вы открываете гигантский топик

                                                              ну что же, тема то действительно интересная :)

                                                              Rust как и C++ не имеет стабильного ABI, так что использование foreign interface (aka C-FFI) отличное решение.

                                                              скорее всего единственно возможное. Поскольку нужно предоставить возможность использовать существующее ПО. Пока вижу что индустрия так устроена, что все хотят использовать свои наработки. Вон в банках до сих пор еще всякие VAX архитектуры и майнфреймы s/360 используют, плюс язык COBOL.

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

                                                              На счет ОС общего назначения, ну можно начать с ОС специального назначения, мы например хотим какой то модуль или драйвер написать. Но вот с драйверами как раз и показательная ситуация, сейчас определяющим является поддержка аппаратуры. В свое время мы даже хотели сделать совместимость с драйверами linux (но решили что частичной совместимости достаточно) и добавили других фишек, типа использование bsp от производителя. это я к тому, что без использования драйверов написанных на Си, вряд ли получиться что то используемое. А если не используемое, то опять канет в лету.

                                                              А вот почему Rust'овое управление памятью чертовски безопасное (более безопасное, чем даже в языках с garbage collector'ом), быстро не описать.

                                                              Вот прямо очень был бы благодарен, если пусть не быстро, а в отдельной статье, но Вы описали «почему». Сами занимаемся управлением памяти в проекте, и всякие тонкости очень интересны! :)
                                                                +3
                                                                Вот прямо очень был бы благодарен, если пусть не быстро, а в отдельной статье, но Вы описали «почему». Сами занимаемся управлением памяти в проекте, и всякие тонкости очень интересны! :)

                                                                Могу объяснить в двух словах.


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


                                                                Во-вторых, в Rust переменная уничтожается после переноса, что вместе с прошлым пунктом исключает класс ошибок use after free. Причем исключает статически.


                                                                Сравните:


                                                                // Си
                                                                struct Foo *foo;
                                                                // ...
                                                                bar(foo);
                                                                baz(foo->x); // упс, а foo уже нет - и мы это поймем только по ошибке памяти (если нам повезет)

                                                                // C++
                                                                std::unique_ptr<Foo> foo;
                                                                // ...
                                                                bar(std::move(foo));
                                                                baz(foo->x); // упс, исключение

                                                                // Rust
                                                                let foo: Box<Foo>;
                                                                // ...
                                                                bar(foo);
                                                                baz(foo.x); // ошибка компиляции
                                                                  0
                                                                  Спасибо.
                                                                  Правда я имел в виду как это реализовано.
                                                                  То есть если идет статический анализ, то как он вообще может отследить путь если ссылка отдается во вне, и статический анализ достаточно долгая штука.
                                                                    +2

                                                                    Этот анализ никогда не выходит за пределы одной функции. Система типов Rust позволяет выразить утверждение, что переменная foo проживет, по крайней мере, столько же сколько и переменная bar. И если такого отношения между "внёй" и переменной нет — то ссылку на переменную передавать "во вню" нельзя.

                                                                      0
                                                                      Понятно, спасибо!
                                                                      +2
                                                                      У каждой ссылки в Rust есть lifetime, т.е. время жизни. Компилятор проверяет, что время жизни ссылки не превышает время жизни переменной, на которую она ссылается. Вот очень простой пример кода, который в Rust не скомпилируется:
                                                                      fn get_ref_wrong<'a>() -> &'a i32 {
                                                                          let s = 1;
                                                                          
                                                                          return &s;
                                                                      }
                                                                      

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

                                                                        За пример спасибо!
                                                                          +2
                                                                          Ну это очень простой пример, исключительно показать концепцию.
                                                                          Но эта концепция работает везде, например, если вы хотите сохранить в структуре ссылку, то должны гарантировать, что ваша структура не будет существовать дольше, чем переменная, на которую вы взяли ссылку.
                                                                          Так же ссылки по умолчанию иммутабельные, если вы хотите изменять данные по ссылке, вам понадобится явно это указать &mut data. Rust позволяет создать много иммутабельных ссылок и только одну мутабельную, если уже есть иммутабельная ссылка, то создать мутабельную нельзя — будет ошибка компиляции, и наоборот.

                                                                          По расту есть хорошая книга, по крайней мере лучше чем официальный растбук — Блэнди Дж., Орендорф Дж. — Программирование на языке Rust. Там относительно неплохо объясняется работа со ссылками, концепции владения и заимствования.
                                                                            0
                                                                            По сути, то за чем следит программист и приличные практики программирования, вынесены в синтаксис языка?
                                                                            Конечно должны быть соглашения о том; кто выделяет, кто освобождает и кто может модифицировать данные по ссылке. Они есть всегда! Если нет, то проект быстро развалится!
                                                                              +2
                                                                              По сути, то за чем следит программист и приличные практики программирования, вынесены в синтаксис языка?
                                                                              Верно. Только не в синтаксис, а в семантику. В подавляющем большинстве случаев, в плане синтаксиса код не отличается от похожих языков. Существует такая штука как lifetime elision которая позволяет опускать тривиальные определения в тех случаях где все однозначно.
                                                                                0
                                                                                В общем, нужно попробовать на чем нибудь небольшом, чтобы проникнуться идеями.
                                                                          +1
                                                                          Проблема не в передаче ссылки как таковой, а в отсутствии контроля за ее временем жизни. Когда вы передаете параметры в функцию они тоже вполне могут лежать на стеке и использоваться по указателю.

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

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

                                                                          Таким образом ситуации вроде use after free, double free, инвалидации итератора или состояния гонок оказываются невозможными.
                                                                            0
                                                                            В классических языках ответственность лежит на программисте. Rust это контролирует явно

                                                                            Да. Написал об этом выше в комментарии
                                                                            +3

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


                                                                            Вот эта штука, когда компилятор всё время озабочен тем, кто владеет, кто не владеет, кто когда завершается — это офигенно. Оно ловит огромное количество багов вокруг mutable/shared, а "обходные пути" вокруг ругани компиляторов обычно оказываются очень правильными архитектурными решениями.

                                                                              +1

                                                                              Ну вот вам более реалистичный пример


                                                                              #include <memory>
                                                                              #include <iostream>
                                                                              #include <functional>
                                                                              
                                                                              std::function<int(void)> f(std::shared_ptr<int> x) {
                                                                                  return [&]() { return *x; };
                                                                              }
                                                                              
                                                                              int main() {
                                                                                  std::function<int(void)> y(nullptr);
                                                                                  {
                                                                                      std::shared_ptr<int> x(std::make_shared<int>(4));
                                                                                      y = f(x);
                                                                                  }
                                                                                  std::cout << y() << std::endl;
                                                                              }

                                                                              Тут та же история, но она уже припрятана под кучкой shared_ptr, которые правда не помогают.


                                                                              Если же его наивно перенести на раст


                                                                              fn f<'a>(x: &'a i32) -> impl Fn() -> i32 + 'a {
                                                                                  move || *x
                                                                              }
                                                                              
                                                                              fn main() {
                                                                                  let y;
                                                                                  {
                                                                                      let x = 5;
                                                                                      y = f(&x);
                                                                                      println!("{}", y());
                                                                                  }
                                                                                  println!("{}", y());
                                                                              }

                                                                              То получите ошибку


                                                                              error[E0597]: `x` does not live long enough
                                                                                --> src/main.rs:9:15
                                                                                 |
                                                                              9  |         y = f(&x);
                                                                                 |               ^^ borrowed value does not live long enough
                                                                              10 |         println!("{}", y());
                                                                              11 |     }
                                                                                 |     - `x` dropped here while still borrowed
                                                                              12 |     println!("{}", y());
                                                                                 |                    - borrow later used here

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


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

                                                                                0

                                                                                Примеры тут не совсем эквивалентны, в плюсовом коде ошибка не в main, а в функции f.

                                                                                  0

                                                                                  Я не переписывал 1в1, потому что это невозможно, а пытался догадаться, что хотел программист этим кодом сделать. Я предположил, что он хотел воспользовать x по ссылке в лямбде, что и изобразил в расте.

                                                                                  +2
                                                                                  Пытаюсь понять, какой вариант выглядит более вырвиглазно — плюсовый или растовый…
                                                                                    0

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


                                                                                    fn f(x: &i32) -> impl Fn() -> i32 + '_ {
                                                                                        move || *x
                                                                                    }
                                                                                      0
                                                                                      Поскольку я с этим языком не знаком в достаточной мере, то отчасти моя реакция вызвана банальным непониманием написанного. Но мне кажется также, что синтаксис у языка объективно вырвиглазный. Как и у шаблонизированного кода на плюсах с использованием стандартной библиотеки. Хотя с Растом все даже хуже. Не зная ничего о шаблонах С++, можно тем не менее по наитию понять, что же там написано. Глядя же на первый вариант растового кода (с генериком) я вообще не понимаю «что хотел сказать автор». Да, еще раз, дело в незнании языка, но кажется, что это положение дел весьма показательно.
                                                                                        0

                                                                                        Нет, просто тут написано тупо больше, чем обычно пишут. Если вы видите кода в 2 раза больше, то и читать его в целом в 2 раза труднее.


                                                                                        Давайте разберем:


                                                                                        // объявляем функцию
                                                                                        fn 
                                                                                        // с единственным генерик-параметром 'a. Лаймтаймы обозначаются таким образом, достаточно быстро привыкаешь
                                                                                        f<'a>
                                                                                        // принимаем референс на i32, который живет не меньше чем 'a
                                                                                        (x: &'a i32) 
                                                                                        // возвращаем тип, реализующий трейт `Fn() -> i32` и живущий не меньше чем 'a.
                                                                                        -> impl Fn() -> i32 + 'a {
                                                                                            move || *x
                                                                                        }

                                                                                        Иными словами, мы говорим "я хочу вернуть лямбду, которой можно пользоваться все время, пока жива переменная x". Какие вещи тут непонятны. impl? Это просто экзистенциальный тип. В C#/Java за этим обычно скрывается просто бокс с интерфейсом, в хрусте компилятор подставит конкретный тип. Поэтому в расте можно вернуть какую-нибудь анонимную структуру, а в том же C# анонимный класс вернуть не получится, потому что его тип записать нельзя.


                                                                                        Да, еще раз, дело в незнании языка, но кажется, что это положение дел весьма показательно.

                                                                                        Не знаю, как по мне все достаточно просто. Причем я не плюсовик ни разу, посмотрите мои статьи, я C# разраб. И мне все это достаточно очевидно. Скажите, что конкретно в этой записи вас смущает, я просто серьезно не могу понять, что тут сложного, не считая б0льшего объема информации.


                                                                                        Просто если попробуете все то же записать при помощи той же джавы, у вас кода будете еще больше. Ну то есть как-то типа


                                                                                        @DeriveOutputType(@FunctionalInterface(int))
                                                                                        @BindLifetimeName(a)
                                                                                        FuncInt f(
                                                                                           @BindLifetimeName(a)
                                                                                           Reference<int> x
                                                                                        ) {
                                                                                           return MoveVariableOwnership(FuncInt(x))
                                                                                        }

                                                                                        стало ли понятнее?

                                                                                          0
                                                                                          Во-первых спасибо за объяснения!

                                                                                          Скажите, что конкретно в этой записи вас смущает


                                                                                          Проблема в том, что смущает буквально все. Что-то конкретное трудно назвать.

                                                                                          я просто серьезно не могу понять, что тут сложного, не считая б0льшего объема информации


                                                                                          Вот в этом «не считая» кроется основная проблема — информации много, но понимания она не добавляет.

                                                                                          Просто если попробуете все то же записать при помощи той же джавы, у вас кода будете еще больше


                                                                                          И очень хорошо — кода больше, и он внезапно понятнее! То есть в Джаве введена разумная избыточность. И хотя я не понимаю, что в этом коде собственно происходит, но его синтаксис хотя бы понятен.
                                                                                            +1
                                                                                            И очень хорошо — кода больше, и он внезапно понятнее!

                                                                                            Тогда это просто вопрос привычки. Ну примерно как после паскаля с begin/end перейти на Си.


                                                                                            Могу посоветовать смотреть на разные языки. Обычно классика считается один си-подобный императивный, один логический, один функциональный, ну и sql. Нужно понимать, что привычный синтаксис не значит удобный. И соовтетственно


                                                                                            То есть в Джаве введена разумная избыточность.

                                                                                            Нет, просто вы привыкли её видеть.


                                                                                            И хотя я не понимаю, что в этом коде собственно происходит, но его синтаксис хотя бы понятен.

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

                                                                                              0
                                                                                              Тогда это просто вопрос привычки. Ну примерно как после паскаля с begin/end перейти на Си.
                                                                                              Могу посоветовать смотреть на разные языки. Обычно классика считается один си-подобный императивный, один логический, один функциональный, ну и sql. Нужно понимать, что привычный синтаксис не значит удобный. И соовтетственно


                                                                                              Да ну нет же! То есть конечно фактор привычки нельзя игнорировать, но он не ключевой.

                                                                                              Насчет Паскаля — перейдя с него на Си я очень порадовался, что вместо begin/end появились брекеты. Их конечно тоже надо уметь готовить, но они гораздо понятнее. И вообще я очень быстро «отошел» от паскалевских заморочек, именно потому, что Си понятнее.

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

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

                                                                                              Нет, просто вы привыкли её видеть


                                                                                              Да конечно, я на Джаве писал сто лет назад, и это была другая Джава.

                                                                                              Например, эрик липперт в статье про «топ 10 фич сишарпа о которых мы жалеем» в один из топа списка поставил «зря мы взяли из сишки то, что тип пишется впереди имени функции и переменных»


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

                                                                                              Выпишите просто что вас смущает.


                                                                                              Проще сказать, что я смог понять сам (если игнорировать ваши разъяснения). А именно — имею догадку, что «i32» как-то соотносится с int32_t, но это не точно. Еще есть смутное подозрение, что "&" имеет отношение к взятию адреса (то есть это ссылка на что-то, возможно это ref/out), но и это не точно. Вот и все.
                                                                                                +1
                                                                                                Насчет SQL — отличный пример, я написал в свое время немало запросов. И мне нравится лаконичность и внятность этого языка. Я сразу начал понимать, что и как там делается, без длительных объяснений. То есть внезапно беда не в императивном клинче моего мозга.

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


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

                                                                                                Ну вот вам аргументы, почитайте.


                                                                                                Проще сказать, что я смог понять сам (если игнорировать ваши разъяснения). А именно — имею догадку, что «i32» как-то соотносится с int32_t, но это не точно. Еще есть смутное подозрение, что "&" имеет отношение к взятию адреса (то есть это ссылка на что-то, возможно это ref/out), но и это не точно. Вот и все.

                                                                                                Ну все так и есть. Возьмем еще раз


                                                                                                fn f(x: &i32) -> impl Fn() -> i32 + '_ {

                                                                                                Объявляем функцию f с параметром x типа ссылка на 32битное знаковое целое, которая возвращает тип, реализующий интерфейс () -> i32, то есть лямбду, возвращающую целое 32битное знаковое целое, и имеющее время жизни такое же, как входной аргумент.


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

                                                                                                  0
                                                                                                  Просто язык достаточно бедный


                                                                                                  Само собой, но вы ведь сами привели его в пример.

                                                                                                  Возьмите какой-нибудь другой бедный язык, будет ли он так же понятен?

                                                                                                  Объявляем функцию f с параметром x типа ссылка на 32битное знаковое целое, которая возвращает тип, реализующий интерфейс () -> i32, то есть лямбду, возвращающую целое 32битное знаковое целое, и имеющее время жизни такое же, как входной аргумент.


                                                                                                  Наверное сложность понимания обусловлена также и сложностью примера. Потому что из текстового описания у меня например формируется вопрос «а зачем это нужно?» )))
                                                                                                  +4

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


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


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


                                                                                                  Это, конечно, не серебряная пуля и не избавляет от всех багов вообще, но за то, от чего избавляет — это не такая уж и высокая цена писать всё чуть более многословно. Тем более, разработчики языка постарались насколько это возможно многословность нивелировать синтаксическим сахаром.


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

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

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


                                                                                                      Ещё есть интересная особенность, касающаяся любого языка: когда у языка появляется новое свойство, большинство, с этим свойством не знакомые, желают более "вербозный" синтаксис. Опытные же пользователи, привыкшие к этому свойству, желают его записывать покомпактней. Этот вопрос регулярно всплывает, когда обсуждается будущий дизайн новых свойств Rust (весь процесс, кстати, происходит открыто и с участием всех желающих).

                                                                                                        0
                                                                                                        Ещё есть интересная особенность, касающаяся любого языка: когда у языка появляется новое свойство, большинство, с этим свойством не знакомые, желают более «вербозный» синтаксис. Опытные же пользователи, привыкшие к этому свойству, желают его записывать покомпактней.


                                                                                                        Угу, и что же, в большинстве вменяемых языковых систем кто побеждает?
                                                                                                          0

                                                                                                          Вторые.

                                                                                                            0
                                                                                                            Как-то я не наблюдаю этого на примере естественных языков.
                                                                                                    0
                                                                                                    Насчет Паскаля — перейдя с него на Си я очень порадовался, что вместо begin/end появились брекеты
                                                                                                    А переходя с Clarion (1986)-- огорчились бы:
                                                                                                    If x = 5
                                                                                                      y = z * 3
                                                                                                    .


                                                                                                    В Modula-2 (1979), ADA ( стандарт и первый сертифицированный компилятор — 1983) и Oberon «детская болезнь» Алгола-60 решена на уровне синтаксиса языка.

                                                                                                    В экосистеме Си — внесли в Misra C указание для носителей «естественного интеллекта».
                                                                                                  +2
                                                                                                  То есть в Джаве введена разумная избыточность.

                                                                                                  Популярность Котлина доказывает обратное.

                                                                                                    0
                                                                                                    Не могу ничего сказать про Котлин, да и про Джаву мало что знаю (изучал в институте сто лет назад), так что я комментировал конкретный пример, и только.
                                                                                    +1

                                                                                    В Rust все сделано банально "вовне" ссылку передать нельзя :) Period.

                                                                                      0
                                                                                      То есть, для системных нужд его без unsafe не получится использовать?
                                                                                        0

                                                                                        Ну на низком уровне, где идёт работа с ресурсами (выделение, уничтожение) — скорее всего, да.

                                                                                          +3
                                                                                          Я не знаю что имел в виду KanuTaH коворя о «вовне», но unsafe совершенно ортогонален всему этому. Основная идея — разделение кода на безопасные и потенциально-опасные части. Если интерфейс модулей спроектирован верно, и инварианты контролируются, то все должно быть нормально.

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

                                                                                          Например, в операционной системе Redox, написаной на Rust, unsafe встерчается только в строго ограниченных местах, тогда как бизнес логика, будь то менеджер страниц или диспетчер многозадачности, описывается на безопасном подмножестве.
                                                                                    +3
                                                                                    Вот прямо очень был бы благодарен, если пусть не быстро, а в отдельной статье, но Вы описали «почему».
                                                                                    Могу посоветовать классический уже пост одного из отцов основателей на эту тему: Fearless Concurrency.

                                                                                    Ну и выше уже писали, что unsafe не отключает проверки, он разрешает дополнительные потенциально опасные операции (и это важно). Что именно происходит хорошо описано тут: You can’t “turn off the borrow checker” in Rust.
                                                                                      0
                                                                                      спасибо!
                                                                                        +4
                                                                                        Всегда пожалуйста. Если что, с вопросами можете обращаться в личку.

                                                                                        P.S.: Про разработку embedded категорически рекомендую блог человека, стоящего на острие прогресса Rust в этой области. По сути он и есть прогресс: blog.japaric.io

                                                                                        Там же вы можете увидеть примеры фантастического API который позволяет статически на этапе компиляции контролировать использование ресурсов и не допускать типичных проблем с памятью и ресурсами. Я думаю подобные вещи гораздо лучше помогут вам оценить преимущества Rust нежели стандартные статьи, ориентированные на широкую публику.
                                                                                          +1
                                                                                          Хорошо, спасибо. Если что обратимся :)
                                                                                          Блог прикольный!
                                                                                    0
                                                                                    но под общую гребёнку попадают и потенциально полезные (конкурентное изменение общего состояния)

                                                                                    Но ведь в Rust есть все нужные примитивы для этой цели...

                                                                                  0
                                                                                  умеет быть совместимым в обе стороны с С-ABI.

                                                                                  Вообще-то С++ так тоже умеет, extern "C" вроде же как раз для этого сделан...

                                                                                    0
                                                                                    Рещил как-то попробывать rust — впечатление смешанные.
                                                                                    1. скачать инсталятор для windows — квест
                                                                                    2. скачал инсталятор для 32bit windows запустил и он бодро установил 64bit rust вместо 32bit
                                                                                    3. обнаружил в директории .cargo/bin файлы идентичны по 5.7Мб которые по сути являются ссылками. ( 67мб просто 12 ссылок )
                                                                                    4. побывал специально на слабой машине — rust очень тормозной в сравнении с другими тормознее только cuda-вский компилятор.

                                                                                    Весь такой системный язык так невнимательно относится к системе.
                                                                                    Выглядело так что сейчас этого синкансена придётся тащить на буксире.
                                                                                      0
                                                                                      обнаружил в директории .cargo/bin файлы идентичны по 5.7Мб которые по сути являются ссылками. ( 67мб просто 12 ссылок )

                                                                                      Так это же и правда ссылки: на диске файл хранится всего в одном экземпляре, просто у него есть 12 разных имен.

                                                                                        0
                                                                                        Для тех кто не верит

                                                                                        0

                                                                                        Ну, формально, вам надо просто поставить WSL, а там-то с Rust всё просто супер. Включая кросс-компиляцию под винды.

                                                                                          0
                                                                                          rustup Вам в помощь, и ставьте все, для чего компоновщик есть. Хотя на Windows вроде требуется полный компилятор: или msvc, или mingw32-w64 (он и 32-битный бывает).
                                                                                            0

                                                                                            Ставим Visual Studio Build Tools и имеем всё недостающее. На страничке rustup это вроде было описано.

                                                                                            +2

                                                                                            Чем-то вы страшным занимаетесь, будто вам Рабинович напел Карузо.
                                                                                            Под винду скачивается единственный экзешник, который даже не требует админских прав. Запускается, далее, далее, готово. Для пользователей без опционально требуемой Visual Studio 2017 (для сишных биндов, если будете использовать) можно вместо одного из Далее указать "хочу gnu вместо msvc", поставится сразу легкая версия mingw. В итоге все компактно сложено в ~/.cargo и ~/.rustup, запускается отовсюду, использует все ядра и потоки по умолчанию (может быть потому и тормоза на слабой машине).

                                                                                          +2
                                                                                          Занимаюсь программированием различного Embedded'a на протяжении ~7 лет, скромное мнение:

                                                                                          — Для решения проблем с надежностью есть стандарт MISRA C. Может быть есть и другие, но с ними я не знаком.
                                                                                          — Очень много legacy и того что мы используем каждый день, написано на С. Да все и так я думаю в курсе. Я работал и работаю со многими закрытыми и открытыми DSP-процессорами и ядрами, практически везде используется С89 или С99 для написания к ним прикладных программ. Все кастомные тулчейны и т.п. — это все для С.
                                                                                          — Я бы рад перейти например на тот же Rust. Но на него не переходят в своих тулчейнах Analog Devices, Qualcomm, CEVA, и др. компании. Т.е. как уже было выше отмечено, в первую очередь поддержка должна идти от них.
                                                                                          — Продакшен конечно разный бывает, но лично у нас смотреть в сторону Rust'a начнут, когда появятся нормальные рабочие инструменты от тех же производителей железа, с которыми мы работаем.
                                                                                            0
                                                                                            но лично у нас смотреть в сторону Rust'a начнут, когда появятся нормальные рабочие инструменты от тех же производителей железа, с которыми мы работаем

                                                                                            Все правильно, это однин из главных сдерживающих факторов.
                                                                                            Разработка собстенных средств разработки (как например предлагали на конференции компилятор языка Си для ARM) естественно будет содержать ошибки. И вот как с этим быть непонятно, но когда индустрия дозреет, и будет несколько отлаженных и доступных компиляторов, вот тогда…
                                                                                              +1
                                                                                              Маловероятен, но в принципе возможен и обратный вариант. Например если, условно, www.tockos.org или Embox станут популярными настолько, что вендоры будут видеть в их поддержке конкурентное преимущество и уже сами озаботятся совместимостью тулчейна.

                                                                                              С учетом гарантий, которые дает Rust, мне не кажется это таким уж невероятным, тем более, что существует инициатива по сертификации Rust для критических систем.
                                                                                            0
                                                                                            Если говорить о надежности программ и скорости разработки, то почему не рассматривается язык Ада? Он к тому же и позиционировался как язык для встроенных систем. Ну и «выстрелить себе в ногу» на нем о-очень сложно…
                                                                                            К тому же на нем отлично пишется для микроконтроллеров. Ну и нет абсолютно никакого зоопарка со стандартами и компиляторами. К слову сказать, gcc поддерживает не так много языков, но среди них — Ада.
                                                                                            А так, кажется порой, что абсолютно все возможности современных языков сначала (очень давно) были в Аде, а потом уже в пошли в массы. К тому же, очень-очень мало языков поддерживают параллельное выполнение на уровне самого языка (не библиотек или там классов), а это сейчас все более актуально.
                                                                                            Да что говорить — все же программирование когда-то, похоже, свернуло не туда и не стали популярны Ада, Пролог…
                                                                                              +1
                                                                                              Язык Ада безусловно обсуждался в рамках данной дискуссии и в рамках обсуждения языка Оберон. Кстати, в кулуарах Дмитрий Дагаев на вопрос об Ада сказал, что не хочет использовать его на АЭС (а использовал Оберон) поскольку сейчас существует только один сертифицированный компилятор для подобных систем и как Вы понимаете он не у нас разрабатывается и его просто не продают.
                                                                                              Еще возникает вопрос с кросс-платформенностью, но это по идее должен решать gcc.
                                                                                                0
                                                                                                Как будто существует сертифицированный компилятор Оберона…

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

                                                                                                Ада — это цельный продукт, но она не сильно то проще С++ %-) И ее реализации вполне могут быть неполными — без менеджера памяти, например.
                                                                                                  +1
                                                                                                  О) компилятор Оберона … Там (такое) творится
                                                                                                  Если мы возьмём Active Oberon ( см. «доклад про Оберон технологии» ) «за основу», то всё будет выглядеть, как правило, «диаметрально противоположно». Другие языки семейства — не менее полезны и «результативны».

                                                                                                  A) Т.к. несколько причастен к «постам и вопросам», приведу сокращённый ответ ( хотя бы, как повод к поиску первоисточника):

                                                                                                  Язык Ада безусловно обсуждался в рамках данной дискуссии и в рамках обсуждения языка Оберон.… на вопрос об Ада…


                                                                                                  Дмитрий Дагаев, «отвечая на посты и вопросы»:

                                                                                                  1. В части функциональной безопасности (...)
                                                                                                  (...) есть компилятор Ады GNAT, но только один ( остальные … ): GNU Ada New York Translator.
                                                                                                  Поэтому использовать его даже для категорий B и C мы не можем. Росатом (...) покупает по конкурсу у трех независимых поставщиков. А тут один (...)
                                                                                                  Более того, даже для категорий B и С продукт должен создаваться в рамках аналогичного жизненного цикла со всеми нашими требованиями к документированию, верификации, валидации и пр.
                                                                                                  (...)
                                                                                                  2. В части категории A, Ада не соответствует требованиям по причине избыточности.
                                                                                                    0
                                                                                                    Active Oberon выглядит неплохо, но компилятор единственный под свою частную песочницу. Существенных проблем (кроме того что рантайм песочницы WinAOS/LinAOS имеет качество некоммерческого студенческого проекта) там отсутствие проверок переполнения/качества вычислений и контроль ошибок только кодами возврата. Принципиальной выгоды перед промышленным стандартом IEC 61131-3 ST я не вижу никакой, скорее наоборот.

                                                                                                    Говорить, что исключаем опенсорсный! компилятор АДЫ из рассмотрения по вышеуказанной причине, имея для АО еще худшую ситуацию — это прямой и явный зашквар (заинтересованное участие в «тендере» выбора решений).
                                                                                                      0
                                                                                                      позволю привести немного переписки от уже упомянутого Дмитрия Дагаева:

                                                                                                      по поводу АДЫ
                                                                                                      Маленькая ремарка в комментариях про Аду: есть одна компания AdaCore и один GNAT — Gnu Ada NewYork Translator. А Росатом даже ластик покупает у 3 независимых поставщиков. А вот остальные разработчики компиляторов Ады связаны с организациями типа Минобороны США. У нас на дне Оберона С.И.Рыбин делал очень интересный доклад https://forum.oberoncore.ru/viewtopic.php?f=155&t=6380&p=107709#p107353 .

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

                                                                                                      По поводу компиляторов и рантаймов:
                                                                                                      Ну и компиляторы размером 3000-50000 строк.

                                                                                                      Время компиляции Оберонов меньше сишных компиляторов в тысячи раз! И есть наша советская школа, например XDS (Алексея Недоря) — оптимизирующий компилятор со скоростью, близкой к компилятору Турбо-Паскаля!
                                                                                                      Количество ошибок компиляторов Оберона очень маленькое, поскольку они простые. Да, бэкенды нужно отлаживать, но программа из 10тыс строк может быть «интеллектуально управляемой», а из 10 млн — нет.
                                                                                                      Для высоких уровней оптимизации есть общая проблема корректности после оптимизации.

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

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

                                                                                                      Скоро выпущу пре-версию Мульти-Оберона, объединив 3 бэкенда: натив X86, трансляцию в С и LLVM.

                                                                                                      LLVM (да и С тоже) как раз в сторону открытого подхода
                                                                                              +3
                                                                                              Тео де Раадт из OpenBSD в своё время разразился хорошим письмом на эту тему:
                                                                                              I wasn't implying. I was stating a fact. There has been no attempt
                                                                                              to move the smallest parts of the ecosystem, to provide replacements
                                                                                              for base POSIX utilities.
                                                                                              > Note that with Cgrep and haskell-ls, there do in fact exist
                                                                                              > implementations/analogues of two of the mentioned utilities in a
                                                                                              > memory safe language (Haskell).

                                                                                              Are they POSIX compliant? No. They are completely different programs
                                                                                              that have borrowed the names.

                                                                                              By the way, this is how long it takes to compile our grep:

                                                                                              0m00.62s real 0m00.63s user 0m00.53s system

                                                                                              Does Cgrep compile in less than 10 minutes?
                                                                                              tl;dr Rust (или любой другой язык) не вытеснил C, потому что никто не пишет на Rust сопоставимые альтернативы.
                                                                                                0
                                                                                                Для некоторых вещей скорость компиляции не так критична. Хотя конечно это важно для массового испольнования.

                                                                                                Проблема с функциональными языками еще и в том, что если у вас ошибка в логике, то никакой язык вас не спасет.
                                                                                                  0
                                                                                                  Проблема с функциональными языками еще и в том, что если у вас ошибка в логике, то никакой язык вас не спасет.
                                                                                                  Ну это справедливо для любого формального языка, не только функционального :)
                                                                                                  0
                                                                                                  Кажется, замену grep'у уже пишут.
                                                                                                    0

                                                                                                    Не просто кажется, но уже давно есть и даже дистрибьютится.

                                                                                                      0
                                                                                                      А, ну вот. Круто ведь!
                                                                                                        0
                                                                                                        Я бы добавил еще что он давно уже используется по умолчанию для поиска по проектам в VSCode.
                                                                                                        0
                                                                                                        В *BSD не линуксовый GNU/grep используется, по-моему.
                                                                                                      0
                                                                                                      Идея заключается в том, чтобы экспортировать (декларировать) интерфейс и объекты могут подключаться именно через этот интерфейс.
                                                                                                      В IDE для WxWorks можно прямо мышкой включать\выключать\настраивать компоненты системы. Соответствующие модули и их зависимости тоже описаны на каком-то языке разметки(сейчас не вспомню уже)
                                                                                                        0
                                                                                                        Ну включать выключать настраивать модули, дело не хитрое, в linux ядре можно спокойно вызвать менюшку написанную на qt, и там прекрасно пощелкать мышкой. Тут все гораздо серьезнее. если я правильно понял то это близко к filter graph.
                                                                                                        А WxWorks 653 имеет описание в xml формате, и там действительно много чего можно настраивать. Но даже у нас в Embox, наверное больше возможностей по конфигурации системы.
                                                                                                        +2
                                                                                                        Вся история IT-индустрии показывает, что по какому-то иррациональному, никому не ведомому признаку программистское сообщество выбирает самый сложный, самый опасный, самый трудный и рандомнобихевористческий инструмент для своих разработок. Примеров есть некоторое количество (С++, js, java, python ). Самое печальное, что эти инструменты занимают лидирующие позиции в рейтинге ЯП. Детально знать и держать в голове тысячу страниц описания с++ не может ни один человек в мире. А уж знать и предвидеть результаты интерференционных явлений, возникающих при использовании десятков разных библиотек, наверное под силу одному-двум суперпрограммистам из близлежащих галактик. В то же время тщательно разработанные инструменты объявляются немеэйнстримными, устаревшими, несовременными и проч. Это поведение коллективного разума IT сообщества невозможно понять. Появляются десятки новых языков уровня КП 3 курса с комьюнити в пару тысяч человек. Это как если бы на заводе инженер в целях самовыражения решил бы в новой машине использовать новые болты с резьбой М13.726 или 4.735. Думаю, что на следующий же день он искал бы новое место работы. Информационные технологии занимают в жизни планеты всё большее место. Результаты использования небезопасных инструментов и технологий мы все знаем. Это постоянно обнаруживаемые уязвимости разного уровня опасности в ОС, приводящие у утечкам конфиденциальных данных, потерям финансовых средств. Методология разработки программного обеспечения, равно как и языков программирования, должны уже давно стать глобальными, наднациональными задачами. Пора уже отбросить узкокорпоративные шоры и погоню за кратковременной выгодой. Основа основ мировой IT структуры — операционные системы и средства разработки должны быть общедоступны и бесплатны. Причем эти основы должны быть сконструированы хоты бы с такой степенью тщательности, как Ада. Да, уже конкретные прикладные пакеты могут быть платными. Но некоторая тщательно проработанная общедоступная база должны быть. Потому что, чем дальше, тем больше появляется несовместимых стандартов и решений, в итоге на решение проблем совместимости уходят громадные ресурсы, которые могли бы быть использованы более продуктивно. (Если что, я сторонник паскале-подобных языков — Ада, Delphi, Оберон, Seed7).
                                                                                                        +3

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

                                                                                                          +1
                                                                                                          М-да, ещё когда я в институте учился, лет 20 назад, ломались копья на тему «C vs Ada/Oberon». Типа вот-вот, ещё чуть-чуть… Прошло 20 лет, а дискуссии все те же :) Ну моднявый Rust ещё появился, да. Но насчет него тоже автор статьи выше совершенно справедливо написал про «5 лет назад» :) Modern language — это, конечно, хорошо, и даже замечательно, но продакшн есть продакшн.
                                                                                                            +1
                                                                                                            Не только Rust появился. Появилось много языков. На Rust как раз до сих пор еще мало пишут. Но всякие Kotlin, Go нашли свою нишу и прекрасно применяются в продакшене.

                                                                                                            А обсуждение очень важно как раз для развития. Время само раставит все по своим местам. Пока C стандарт де факто по крайне мере для системного программирования, но может в будущем появится более лучшая альтернатива!
                                                                                                              +1

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

                                                                                                                0
                                                                                                                Тут согласен, Си для системного программирования пока никто не переплюнул, поэтому все и вкладываются в эту сферу и драйвера и операционки и обучение.
                                                                                                              +2
                                                                                                              Один мой вузовский препод говорил следующее: «Я знал старого одного программиста, он недавно умер, так вот он часто говорил, что Си скоро умрет. Но пока это не произошло — открываем редактор и пишем...»
                                                                                                                +2
                                                                                                                Вывод: Си нас всех ещё переживёт.
                                                                                                              0
                                                                                                              Дело в том что язык Си — очень близок с идеей предварительной компиляции. Ключевое слово — «предварительной». Проверка кода на безопасность должна быть произведена до окончательной сборки.
                                                                                                              То-есть нужно сначала хорошо подумать, для того чтобы ваша новая функция выполняла именно то что вы задумали, и ничего более. Проблема в большом количестве необходимых действий, примитивных по своей сути — но в них можно ошибиться. Это в языках более высокого уровня в функции может быть всего одна или две математические операции — а всё остальное пространство заполняет длиннющие имена переменных. В Си не так, имена короткие — а действий много.

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

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