Pull to refresh

Comments 333

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

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

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

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

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

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

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

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

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

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

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

UPD: Да, где были мои глаза — есть!

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

Если производитель, например, будет заголовочники предоставлять не на Си, а на С++, то можно избежать всякой ерунды…
Ну вот пример, 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? Но видимо, там думать надо было бы :), а тут нормально все стандартами языка можно сразу проверить…
На чистом Си тоже есть static_assert прямой в стандарте (_Static_assert). Для выравнивания есть оператор offsetof, правда нет нормальной стандартной реализации, но огромное количество компиляторов поддерживают его с помощью builtin.

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

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

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

Общий случай, выравнивание по 4 байта, идет 16 битный инт, потом дырка в 2 байта, потом 16 битный инт RESERVED, потом дырка в 2 байта. И компилятор имеет на это полное право, он же не обязан за вас додумывать, что вы хотите два 16 битных инта запихать в одну ячейку памяти 32 битную и в итоге сделает размер этой структуры в 2 раза больше ожидаемого и адреса регистров не те, что ожидает программист. Компиляторы конечно не такие тупые, чтобы дырки всавлять, но в общем случае они должны это сделать исходя из архитектуры микропроцессора. Любой статический анализатор кода руганется жестко с сообщение уровня Ошибка.
_IO это volatile.
Ну право-то он имеет, согласен (чтобы не имел, нужен __attribute__(packed)). Но обычно компиляторы выравнивают поля структур на их размер, то есть char'ы выравниваются побайтно, int16 на 2 байта, int32 — на 4 байта. То есть могут быть дырки в промежутках между char и int16 или int16 и int32, но не между полями одинакового размера (если их, конечно, не выравнивают специально каким-то нестандартным образом через соответствующий атрибут).
Да это скорее всего так для 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.

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

А что, адреса 16-битных регистров ввода-вывода выровнены по границам 2 байт?
Как же они 16 битные, когда архитектура 32 бита. Они 32 битные, просто старшие 16 бит не используются…
image
И какой же вывод? Каковы адрес и смещение относительно базы рассматриваемого 16-битного регистра? Каковы адрес и смещение относительно базы следующего поля? Не на тот ли самый слоп больше?
вывод такой, мы не можем гарантировать, что компилятор сделает то, что мы задумали и не вставит дырки, и поэтому такую структуру без выравнивания использовать нельзя… и надо бы её переделать для данного микроконтроллера вот в такую:
struct Uart
{
  __IO uint32_t SR;         
  __IO uint32_t DR;         
.
.
.
}
Лучше явно указать компилятору необходимость упаковки структуры с помощью соответствующей прагмы или атрибута. Ваш вариант тоже ничего не гарантирует в общем случае, компилятор все еще волен делать любые padding'и, только уже между int32-полями :) На самом деле это обязательно нужно делать при написании переносимого кода, для работы которого важны смещения внутри структур, но если код де-факто не будет переносимым (предполагается работа на конкретной архитектуре и сборка конкретным компилятором), то этим часто пренебрегают.
Нет для 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) ; //Ок, 

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

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

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

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


Что, внезапно, еще более общО и переносимо.
Гарантировать нечего: компилятор не вставит дырки только если это указано в его настройках или параметрах вызова. Покажите пример, где эту структуру размещают в памяти. И пример, где наличие слопа приводит к проблемам, но в реально работающим коде, а не в выдуманном…
Я не могу привести код, потому что текущий 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;

Представленные структуры в плане смещения от начала структуры значимых полей идентичны. Вы пишете в регистр 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 без приведения типа.
Может проще объявлять все регистры 32-битными, каковыми они и являются? Всегда лучше быть честным, чем умным.

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


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

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


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

ISO/IEC TR 18037


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

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


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

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

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


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

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


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

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


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

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

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


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

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

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

Ну не может uint16_t в структуре с фиксированным адресом внезапно занять 4 байта, typedef мешает.
А вот в новой структуре созданной например так:
USART_TypeDef new_usart;
размер переменных может быть увеличен в угоду ускорения общего алгоритма. Но для этого ещё постараться надо.
Просто чтобы не лезть в дебри, читаем документацию на компилятор:
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.
Просто чтобы не лезть в дебри

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

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

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

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

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

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

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


struct foo fixed_addr_var;
struct foo auto_addr_var;

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

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

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

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

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

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

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


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

Все таки относительно редкой, поскольку довольно новая.
Безусловно перспективная, согласен самая быстрорастущая, но посмотрите например сколько дистрибутивов Linux поддерживает ARM и MIPS, а сколько RISC-V? До недавнего времени, это было скорее встроенное решение на основе ядер ПЛИС.
Вопрос про использование 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.
Абсолютно согласен. Rust очень интересен, и мы в Embox на него тоже облизываемся, но пока речь идет о пробе пера, каком нибудь модуле на Rust.

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

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

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

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

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

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

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

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

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

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

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

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


А можно пару примеров, что в синтаксическом новоязе 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 в коде выше, потому что тот не участвует в выражениях) без поллитры не всегда разобраться

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

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

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

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


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

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

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

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

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

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


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

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


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

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


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

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


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

let closure  = |i| i + 1;

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

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


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

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

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

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


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

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


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

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

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


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

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


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

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

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

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


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

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

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

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


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

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

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

Для обозначения переменной нужно два ключевых слова 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 да, может быть неудобен или непривычен. В целом же после небольшой практики и благодаря гораздо более мощному тайпчекеру перестаёт быть проблемой.


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

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

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


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

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

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

Недавно стал смотреть на Nim после раста — впечатления ровно обратные от вашего комментария.

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


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


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

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

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

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


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

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


Совместимость с С-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.

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

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

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

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

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

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

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

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

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

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


struct Bar {
    super: Foo,
}

impl Bar {
    fn baz(&self) { self.super.baz() }
}

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

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

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


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

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


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

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

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

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

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

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

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

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

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

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


Во-первых, 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); // ошибка компиляции
Спасибо.
Правда я имел в виду как это реализовано.
То есть если идет статический анализ, то как он вообще может отследить путь если ссылка отдается во вне, и статический анализ достаточно долгая штука.

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

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

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

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

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

  1. Раздел основного сайта, посвященный embedded www.rust-lang.org/what/embedded
  2. Книга по embedded разработке: rust-embedded.github.io/book
  3. Большое собрание толковых ссылок по теме: github.com/rust-embedded/awesome-embedded-rust
Проблема не в передаче ссылки как таковой, а в отсутствии контроля за ее временем жизни. Когда вы передаете параметры в функцию они тоже вполне могут лежать на стеке и использоваться по указателю.

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

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

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

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

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


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

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


#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

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


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

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

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

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

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


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

Нет, просто тут написано тупо больше, чем обычно пишут. Если вы видите кода в 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льшего объема информации


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

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


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

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


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


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

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


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

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

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


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

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

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

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

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


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

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


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

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


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

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


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

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


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

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


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

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


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

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


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

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

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


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

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


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


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


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


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

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

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


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

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


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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Ну кто ж под виндой разработкой занимается.
Можно в Windows10 в ликуксовой подсистеме набрать apt-get install rustc и не мучится больше.

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

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

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

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

С учетом гарантий, которые дает Rust, мне не кажется это таким уж невероятным, тем более, что существует инициатива по сертификации Rust для критических систем.
UFO just landed and posted this here
Язык Ада безусловно обсуждался в рамках данной дискуссии и в рамках обсуждения языка Оберон. Кстати, в кулуарах Дмитрий Дагаев на вопрос об Ада сказал, что не хочет использовать его на АЭС (а использовал Оберон) поскольку сейчас существует только один сертифицированный компилятор для подобных систем и как Вы понимаете он не у нас разрабатывается и его просто не продают.
Еще возникает вопрос с кросс-платформенностью, но это по идее должен решать gcc.
Как будто существует сертифицированный компилятор Оберона…

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

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

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

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


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

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

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

по поводу АДЫ
Маленькая ремарка в комментариях про Аду: есть одна компания 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 (да и С тоже) как раз в сторону открытого подхода
Тео де Раадт из 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 сопоставимые альтернативы.
Для некоторых вещей скорость компиляции не так критична. Хотя конечно это важно для массового испольнования.

Проблема с функциональными языками еще и в том, что если у вас ошибка в логике, то никакой язык вас не спасет.
Проблема с функциональными языками еще и в том, что если у вас ошибка в логике, то никакой язык вас не спасет.
Ну это справедливо для любого формального языка, не только функционального :)
Кажется, замену grep'у уже пишут.
Я бы добавил еще что он давно уже используется по умолчанию для поиска по проектам в VSCode.
Идея заключается в том, чтобы экспортировать (декларировать) интерфейс и объекты могут подключаться именно через этот интерфейс.
В IDE для WxWorks можно прямо мышкой включать\выключать\настраивать компоненты системы. Соответствующие модули и их зависимости тоже описаны на каком-то языке разметки(сейчас не вспомню уже)
Ну включать выключать настраивать модули, дело не хитрое, в linux ядре можно спокойно вызвать менюшку написанную на qt, и там прекрасно пощелкать мышкой. Тут все гораздо серьезнее. если я правильно понял то это близко к filter graph.
А WxWorks 653 имеет описание в xml формате, и там действительно много чего можно настраивать. Но даже у нас в Embox, наверное больше возможностей по конфигурации системы.
UFO just landed and posted this here
Основа основ мировой IT структуры — операционные системы и средства разработки должны быть общедоступны и бесплатны.

Ну так opensource есть, Linux gcc gdb?
Причем эти основы должны быть сконструированы хоты бы с такой степенью тщательности, как Ада.

Ну есть другой подход делать надежные программы, «Собор и базар»

(Если что, я сторонник паскале-подобных языков — Ада, Delphi, Оберон, Seed7)

Дело вкуса, я уж точно не противник этих языков.
Можно долго холиварить по поводу какой язык лучше. Но мне кажется, что время покажет для каких задач подходит тот или иной язык. Наприме, java задумывался как язык для всех типов платформ, кросплатформенный. В итоге основное серверная часть была как раз на нем написана, наверное для этих целей он был наиболее хорош, но это же не маленькие устройства, хотя попытки постоянно были. ой забыл про Android, но например Kotlin, замечательно зашел в этом плане как замена Java. Или python, сейчас на нем делают очень много прототипов и проводят моделирование, язык лучше отвечает характеристикам для подобных задач. Есть старые языки, которые почему то ушли в прошлое, есть языки которые так и не нашли свою нишу.

В общем, я стороник opensource, а языки нужны разные для разных целей. А если Вы сторонник Оберона почему бы не присоединиться к проекту по обучению этому языку Информатика 21
Вся история IT-индустрии показывает, что по какому-то иррациональному, никому не ведомому признаку программистское сообщество выбирает самый сложный, самый опасный, самый трудный и рандомнобихевористческий инструмент для своих разработок.
Две теории, почему так:

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

Вторая теория — «гандикапы» Амоца Захави. Она вот о чем: самки выбирают самцов с вредным признаком, потому что выживание таких самцов свидетельствует об их высокой приспособленности. Гены этой приспособленности унаследуют не только сыновья, но и дочери, то есть в совокупности такой выбор окажется полезен.


Вспоминая Докинза (С)

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

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

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

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

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

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

Я утверждаю, проблема безопасности Си — это полное отсутствие инструментов проверки/подсказки алгоритмов пользователя во время его набора. Когда появится поддержка — все вопросы отпадут сами собой.
Даже если таких инструментов нет прямо в IDE, то это решается путем создания правильного процесса CI. Перед тем, как попасть в основную ветку, новый код должен быть в обязательном порядке и автоматически проверен всеми используемыми анализаторами и пройти все тесты. Без этого merge просто не должен проходить. А уж инструментов для решения подобных задач вагон и маленькая тележка. Но и все эти анализаторы не дают 100% гарантии отсутствия ошибок. Впрочем, расты с оберонами точно так же сами по себе таких гарантий не дают.
UFO just landed and posted this here
Clion вполне себе на ходу делает статический анализ кода…
А ведь я проверял… QtCreator не различает в параметрах функции: числовые/символьные константы, горячие переменные, и перемененные с произвольной разрядностью. Видеть их видит, а связать поведение алгоритма с их типом не может.

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

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

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

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

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

Проблема безопасности в Си — что для него фундаментально невозможно написать анализатор который поймает достаточно количество багов, чтобы считать язык безопасным. Ну физически, если у вас сложение двух числе это УБ то вам никакой анализатор не поможет. Потому что если у вас 90% ложноположительных срабатываний, то по сути инструмента и нет. Не помню, где читал, но для нормальной работы инструмент должен давать меньше 5% ложноположительных срабатываний.


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


В этом плане Джон Кармак очень хорошо высказался в своем твиттере


Coincidentally, I just started writing some rust… I find this sentiment strange; people don’t look to other languages because you can’t do something in c++, but more often because you can.
Перед тем, как попасть в основную ветку

Я о том и говорю — автоматический анализ должен быть в самой IDE. Чтобы встроенная!!! (а кстати почему они все внешние?) система контроля версий не допускала сохранения заведомо ошибочного кода.
То-есть проблема не в языке, а в программном обеспечении для работы с ним.
Я о том и говорю — автоматический анализ должен быть в самой IDE.

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

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

А в чем проблема-то? Мы же не говорим, что русский плохой, потому что в нем можно построить грамматически корректные фразы, которые при этом не несут смысла, "не работают". И уж тем более не бежим создавать новый просто из-за того, что люди страдают с выражением своих мыслей на существующем

Если бы мы писали программы на русском, то это был бы плохой язык, да.


От него не требуется даже той толики строгости, которая требуется для ЯП.

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

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


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

например, у пилотов гражданской авиации

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


что делать с этим

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

+1. Люди застраховали свой зад от какого-то определённого класса ошибок в каких-то определённых случаях (по крайней мере, они так считают), и носятся с этим, как будто это решит все проблемы разработки ПО. Это не говоря уж о том, что everything comes for a price (причем даже не только и не столько в виде какого-то рантайм оверхеда, сколько в необходимости изобретать какие-то обходные пути там, где ранее все "просто работало" — с умеренным приложением головы, разумеется).

Programming Defeatism: No technique will remove all bugs, so let's go with what worked in the 70s.

Nope, я скорее про "закон дырявых абстракций" и "бесплатного сыра не бывает" :) Если бы "наворачиванием абстракции на абстракцию" можно было решать любые проблемы — ядра ОС и прошивки для железа уже писали бы на яве с шарпом. Там такое любят :)

Nope, я скорее про "закон дырявых абстракций" и "бесплатного сыра не бывает" :)

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


Если бы "наворачиванием абстракции на абстракцию" можно было решать любые проблемы — ядра ОС и прошивки для железа уже писали бы на яве с шарпом. Там такое любят :)

Андроид на яве и написан. Singularity — на шарпах. Что до винды и линухов, тут то что называется "исторически сложилось". Нет никаких причин почему именно си, просто так вышло. Потому что популярно было в 70е. в нулевых популярной была жаба, андроид написали на ней. Сейчас раст достаточно популярен, фукси (новая ос от гугла вместо андроида) емнип на нем пишется.


Так что прогресс идет.

Ядро Android написано на C/C++, никакой явой там и не пахнет. Ява там только как рантайм для приложений (и то не для всех — Android NDK никто не отменял).

Я не считал точно, но жава-строк в андроиде явно больше, чем код ядра. Вся std библиотека и все остальное — это джава.

Да, основной рантайм для пользовательских приложений там — это Java-классы (но не только, есть ещё и NDK). Но не ядро.

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

Ну то есть "пишите код без багов". Так не бывает.


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


Напомню, что человек не может держать в памяти больше 7 объектов одновременно, и это не зависит от квалификации.


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

Ну и отлично. Что расстраиваться-то?

Так не бывает

Ну понятное дело, но и смена языка тоже не спасет)
Про помнить каждую переменную и количество объектов не понял, опять же, в чем именно си хуже любого другого языка. К слову, в нем нет NULL'ов, зато есть самые обычные нули


Что расстраиваться-то?

Как чего, падению квалификации. Софт-то кому-то писать надо, нам же его и использовать, если доживем

Ну понятное дело, но и смена языка тоже не спасет)

Вполне. От некоторого класса проблем. Чем серьезнее язык, тем больший этот класс.


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

Ну вот я не могу без подсказки от системы типов что это Option<T> помнить, что тут нулл выскочить может.


Как чего, падению квалификации. Софт-то кому-то писать надо, нам же его и использовать, если доживем

Ну а это типичное "раньше было лучше".

Ну а это типичное «раньше было лучше».

Ну, смотря в чем «лучше». Типичный Java/C# (а тем более JS) разработчик сейчас, как правило, не имеет понятия ни о том, как работать с памятью, ни о приемах оптимизации кода в плане правильного использования кешей, ни о том, как внутри себя устроены какие-нибудь мутексы, и к чему приводит их использование в плане производительности. Да что там говорить, он даже не особо интересуется, к чему «внутри» приводят его попытки конкатенации строк «в лоб», через оператор "+". Не царское то дело. Как только нужно будет написать что-то действительно оптимальное, такой разработчик тут же сдуется, упрется в порог инструментария. Он просто не будет знать, что можно как-то по-другому. С другой стороны, человек, имеющий опыт относительно низкоуровневого программирования, как правило, все же задается вопросом «а что там под капотом», поэтому он даже на всех этих «абстракциях» пишет лучше, чем граждане, пишущие исключительно на «удобных» языках, а главное — он всегда имеет выбор.

P.S. Вот выше johnfound написал «все выше пишут как будто производительность все еще удваивается каждые 18 месяцев», его сначала даже заминусовали, я помню, а я вот сразу понял, о чем он. У меня те же ощущения.
Ну, смотря в чем «лучше». Типичный Java/C# (а тем более JS) разработчик сейчас, как правило, не имеет понятия ни о том, как работать с памятью, ни о приемах оптимизации кода в плане правильного использования кешей, ни о том, как внутри себя устроены какие-нибудь мутексы, и к чему приводит их использование в плане производительности.

Да-да, а типичный C++ разработчик не знает о поколениях ГЦ, как работает хотсвап джиттер и прочее. Что из этого следует?


Да что там говорить, он даже не особо интересуется, к чему «внутри» приводят его попытки конкатенации строк «в лоб», через оператор "+".

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




Советую не тешить в себе ложный элитизм.

Да-да, а типичный C++ разработчик не знает о поколениях ГЦ, как работает хотсвап джиттер и прочее. Что из этого следует?

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

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

Не в курсе про жс, но в Java компилятор таки пытается заменять такие «лобовые» конкатенации на работу через StringBuffer:

docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18.1

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

Советую не тешить в себе ложный элитизм.

:) Я учту :)
Почему же? Если он начал писать на managed-языках, он узнает. Может быть, даже напишет свой. У него даже вполне может быть для этого необходимый background.

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


Не в курсе про жс, но в Java компилятор таки пытается заменять такие «лобовые» конкатенации на работу через StringBuffer:

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


:) Я учту :)

Правда, очень рад. Нечасто такое слышу.

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

На самом деле у меня лично просто есть забавная история как раз про случай, когда оптимизатор JIT'а с этим не справился. Меня просто попросили переписать некий кусок на плюсах, потому что «плюсы же быстрее». Переделав в этом куске конкатенации в цикле в цикле в цикле на StringBuilder (там не требовалась синхронизация), я ускорил кусок в разы for no charge, и продолжил лентяйничать дальше. Это я не с потолка взял пример, это моя личная боль :)))

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

а типичный C++ разработчик не знает о поколениях ГЦ

На самом деле, раньше сборку мусора писали как раз для C/C++

Вполне. От некоторого класса проблем. Чем серьезнее язык, тем больший этот класс.

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


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

Только лучше эту опасную сварку применять точечно, огораживая ~unsafe~ знаком ОСТОРОЖНО: СВАРКА.


И если что-то пошло не так, сразу понятно, куда глядеть.

Но почему? Если человек на естественном (очень гибком и прощающем) языке пишет с ошибками, то мы его ругаем, зовем неграмотным.
Не бывает плохих разработчиков, бывает плохой язык. Странно что ракеты летают, а атомные станции — работают. :)

Ежели серьезно, на мой взгляд, дело в человеке, а не в инструменте. Правда это другая крайность. Безусловно удобные и эффективные инструменты должны быть.
на мой взгляд, дело в человеке, а не в инструменте

Это и моя же позиция)


удобные и эффективные инструменты должны быть

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

То есть, тот же раст на самом деле имеет кучу интересных фич, но зачем-то позиционируется многими как замена си со смущающей меня аргументацией.
А те кто позиционируют — ничего другого не знают. Вы на скольких языках пишете? Я по роду деятельности: ассемблер, СИ, C++, C#, Java, Phyton (web и 1С перечислять не буду, давно в прошлом). Уверен и у вас не один. Ибо данное вами высказывание наталкивает меня именно на такие мысли.

Так тяжело существовать параллельно, что ли?)
Безусловно да. Ибо человек, который знает только один язык, ограничен в восприятии контекста решаемых задач. А значит все должно быть как у него :) «Когда в руках только молоток, все начинает казаться гвоздем».

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

Так же и тут. Я и не против того чтобы все унифицировать. Но наша индустрия еще не выработала всего нужного. Есть legacy, есть лишнее, а что-то отсутствует. За много лет её существования поменялся ряд задач, которые мы решаем. Многие из них перестали вписываться в ту картину которая сложилась. Нужно переосмысление всего. И как следствие выработка новых подходов, механизмов и аппаратуры. А людей, которые решат данную задачу, просто нет. Потому что и спроса на них нет. А ведь это исследовательская работа, которая требует очень длительного вовлечения по времени. Ситуация осложнена тем, что корпорации деньги зарабатывают. И развитие как таковое отсутствует. Рынок насытился, и все думают о том чтобы прибыль осталась на том же уровне.

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

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

Неудобство понятие относительное. Например, ассемблер неудобнее Си, а си неудобнее раста. Через 20 лет будет язык удобнее их всех. И еще через 20. Развитие в том и заключается, что палки-копалки и камни превращаются в экскаваторы и отбойные молотки. Заметьте, мы не заставляем людей научиться выкапывать по 20 тонн земли в час, мы меняем инструменты. Даже если взять лучших копателей за всю историю и заставить учить людей как это делается вы не сможете достичь результатов техники. Потому что люди это люди. Они ошибаются, они часто теряют внимание, да и в целом рассеяные. Ожидать от них полной самоотдачи и внимательности 24/7 немного наивно. Лучше дать инструмент, который скажет "чел, ты переменную используешь, я такой не вижу. Может ты ошибся"? или "А тут у тебя ошибка может возникнуть, а ты никак не обрабатываешЬ", или "Вот ты версию библиотеки обновил, а вместо Т у тебя тут Option<T> начал приходить, обработай, дорогой".

Например, ассемблер неудобнее Си, а си неудобнее раста

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


Лучше дать инструмент, который ...

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


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


Но на самом деле, 2/3 примеров не пройдут даже лексический анализ

На первый вопрос проще всего взять уже известное мерило


Все языки одинаково мощные, если рассматривать их с точки зрения эквивалентности машине Тьюринга, но это не та мощь, которая важна программисту. (Никто ведь не хотел бы программировать машину Тьюринга). Мощь языка, в которой заинтересован программист, возможно, трудно определить формальными методами, однако одно из объяснений этого понятия заключается в свойствах, которые в менее мощном языке можно получить, только написав на нем интерпретатор для более мощного языка. Если в языке A есть оператор для удаления пробелов из строк, а в языке B его нет, это не делает A более мощным, чем B, так как в B можно написать процедуру, которая делала бы это.

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

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


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

Ну вот я считаю, что в программе не должно быть CVE с памятью вообще. Даже если код "ну типа работает". Это не те проблемы, на которые можно забить в приложении, если только это не прототип.

Никто ведь не хотел бы программировать машину Тьюринга

Мы этим уже занимаемся. Наши физические компьютеры — ее модели, мы просто используем синтаксическую прослойку, которую разворачивают компиляторы, интерпретаторы и виртуальные машины


огораживая ~unsafe~ знаком ОСТОРОЖНО: СВАРКА

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


Ну вот я считаю, что в программе не должно быть CVE с памятью вообще

На два стула сесть не выйдет. Если писать полностью без unsafe, то можно легко натолкнуться на повышенный расход памяти (эти умные указатели любят позависать). Глобально надо смотреть в сторону сборщиков мусора, позволяющих совмещать подходы. И тех же самых, что и для C/C++, динамических анализаторов типа valgrind

Со сборщиками мусора та же фигня: да, простой оторваный цикл они соберут. А вот как бы удаленный объект, забывший отписаться от событий — уже нет...

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

Свободу сборщикам мусора!)
Если честно, не совсем понял, что имеется в виду: при каких-то настройках gc собирает не только освободившуюся память или дурно влияет на корректно работающий код?

Имел ввиду, что gc может ждать, пока память станет свободной по его мнению, а может получить явный вызов по освобождению объекта "здесь и сейчас"


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

"На часть объектов" программист не может сделать вызов GC по определению мусора: если у программиста есть способ указать на объект, то он точно мусором не является.

Почему нет?


int* temp = gc_calloc(BIG_SIZE, sizeof(int));
for (...) {
// работаем с temp'ом
}

// начиная с этого момента массив больше не используется, является мусором в памяти
// сразу освобождаем, чтобы не насиловать сборщик
gc_free(temp);

Как это работает? И что будет, если я сделаю вот так?


int* temp = gc_calloc(BIG_SIZE, sizeof(int));

global_var = temp + 1;

gc_free(temp);

А если без вызова gc_free?

что будет, если я сделаю вот так?

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


Если без вызова — то будет висеть, так как завязан на глобальную переменную, куда ему деться

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

Ну и какие тогда преимущества у подобного сборщика мусора перед нормальными умными указателями?


Если без вызова — то будет висеть, так как завязан на глобальную переменную, куда ему деться

А как он поймет, что есть такая переменная и там находится именно указатель?

Ну и какие тогда преимущества у подобного сборщика мусора перед нормальными умными указателями?

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


А как он поймет, что есть такая переменная и там находится именно указатель?

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


В общем случае, сканируются регистры, стэк и статичные регионы типа data (как раз случай глобальной переменной). Для каждого найденного указателя f просто проверяется, есть ли в базе объектов (обычно это простая таблица) такая пара (p, size), что p <= f < p + size. Если есть — объект, описываемый парой, в использовании, то есть не мусор

… простой оторваный цикл они ( сборщики мусора) соберут. А вот как бы удаленный объект, забывший отписаться от событий — уже нет...
GC прав: «объект, который забыли отписать от событий» — его удалять просто небезопасно…

Прав конечно же. Но утечка ресурсов от этого не исчезает.

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

Увы, нет. И С/С++ с их просто огромным количеством UB/ID тому вполне себе подтверждение. Вы не можете в С сказать "нулевые указатели у меня будут только здесь, в других местах их не пропускать". Так что программа на С/С++ будет представлять из себя здание с огромным ОСТОРОЖНО СВАРКА во весь фасад.


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

Появление UB — это детерменированное поведение. Мы всегда знаем, где он есть, а где его нет, это четко прописано в спецификации. Просто не знаем заранее, какой из возможных результатов скомпилируется. Недетерменированные автоматы же на x86 никак не загнать

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

Поэтому единственно достоверный сопособ исключить UB — предотвратить его статически, на уровне системы типов.
UB sanitizer был бы тривиальным

Большое его подмножество и. Сложно найти неинициализированную переменную? Да ну нет. Знаковое переполнение? Да тоже просто. Нал поинтер? Куда проще


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


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

Пока не вышло

UFO just landed and posted this here

Такой поиск проводится до стадии оптимизаций

UFO just landed and posted this here

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

UFO just landed and posted this here

Ну да, потому что тогда мне моя иде нарисует предупреждение о проверке на NULL. Такие ошибки легко ловятся даже простым фильтром без анализа: необходима проверка либо до доступа, либо после изменения. И кто мы-то, я один тут)

Мы этим уже занимаемся. Наши физические компьютеры — ее модели, мы просто используем синтаксическую прослойку, которую разворачивают компиляторы, интерпретаторы и виртуальные машины

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


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

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


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

С чего это? Ансейф не имеет отношения к повышенному расходу памяти.


(эти умные указатели любят позависать

Все считается в компайл тайм, какие зависания?

вопрос десятый

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


Ансейф не имеет отношения к повышенному расходу памяти… Все считается в компайл тайм

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


какие зависания

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

Только если для страуса в песочнице.

Для большинства софта. Потому что это называется абстракция.


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

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


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

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

Занимался этим на курсе матолгике в универе

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


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

Без "такого" не будет практического программирования, потому что нечем будет компилировать, не на чем исполнять)

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

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


Думаю, нет.

Ох уж это гадание по интернету.


Без "такого" не будет практического программирования, потому что нечем будет компилировать, не на чем исполнять)

Знаю людей, которые никогда такого не делали, но им есть на чем компилировать. Как так?

В машине тьюринга нет никаких регитсров, там есть только бесконечная лента и алфавит

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


Знаю людей, которые никогда такого не делали, но им есть на чем компилировать. Как так?

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

UFO just landed and posted this here
Ну, мне просто интересно, где ваше «надо» заканчивается

Нигде, процесс учебы не является чем-то конечным


И можно было одним постом написать все, а то я аж испугался количеству входящих на почте

UFO just landed and posted this here
UFO just landed and posted this here

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

UFO just landed and posted this here

Пишут много кто и много на чем. Это не значит, что ошибок меньше, а если меньше, то из-за языка


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

UFO just landed and posted this here

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

Например, ассемблер неудобнее Си, а си неудобнее раста

Для многих низкоуровневых задач C удобнее Rust'а. Такие задачи обычно невелики, а синтаксического шума в C меньше, так что меньше и возможность описаться или еще как ошибиться. C создан для таких задач, а Rust делает их решение возможным.
Преимущества у Rust'а появляются при масштабировании задачи.
Не бывает плохих разработчиков, бывает плохой язык. Странно что ракеты летают, а атомные станции — работают. :)

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


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

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

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

Человека нельзя кардинально поменять. Нельзя сказать «с завтрашенго дня пиши без багов».
Речь по-моему не о багах. Кардинально можно уволить. А в утверждения типа «пишет плохо но круто идеи выдает» я давно не верю. Т.к. многократно видел что это не так. И т.к. если человек плохо разбирается в деталях, то и в глобальным смысле он видит еще меньше. Если человек не может кардинально меняться, ему надо менять профессию. Например на стройку пойти работать. Если конечно у него задача найти свою нишу. А если в целом, я не пойму откуда такая любовь к таким людям. Я с такими даже говорить не стану(в профессиональном смысле, профессионализм на человеческие качества никак не влияет). Что уже говорить о том, чтобы считаться с ними. Интересно выходит, делают хуже, а требуют к себе равного отношения. «Защита прав слабоумных».

Человеку можно дать более удобный инструмент, но и все.
Можно, и инструмент нужно улучшать. Но сути само по себе оно не меняет. Если человек на менее удобном инструменте не мог выполнять работу нормально, то он и на более удобном не сильно то себя проявит. Потому что основ не понимает. А бывает еще когда дурака грамота только портит. Скажем так, с удобством инструмента, должны расти и требования к задачам. А если так, то планка по задачам снижаться не будет, с чего бы ради он будет делать нормально, когда в голове больше двух переменных удержать не может? Но если планка не повышается, а инструмент удобнее и проще, и как следствие он ту или иную задачу уже может выполнить, то он, выходит обезьяна. Т.к. по сути по методичке уже делает, не понимая основ. И в том и в другом случае, мне видится, дело в человеке.
Это что-то доказывает? Это доказывает что везде надо применять этот язык? Самолетостроение все-таки несколько иная стезя. И подходы следовательно иные, сугубо специализированные.

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


Речь по-моему не о багах. Кардинально можно уволить.

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


Можно, и инструмент нужно улучшать. Но сути само по себе оно не меняет. Если человек на менее удобном инструменте не мог выполнять работу нормально, то он и на более удобном не сильно то себя проявит. Потому что основ не понимает.

Если человек не знает физику, то микробиологом ему не быть, потому что он основы не понимает.


Простите, но нет. Есть известный закон дырявых абстракций, который явно говорит, что достаточно знать +-1 уровень от своей текущей чтобы полноценно выполнять свою работу. Кругозор — это полезно, никто не спорит.


Но как уже сказано, знание "С++" никак не делает челвоека более хорошим разработчиком, чем знание C#.

Просто если есть бесплатные бенифиты, то почему бы ими не воспользоваться?
Можно воспользоваться, кто спорит то. А что до этих бенефитов, они в самолетостроении не просто, а потому что там ошибка стоить дорого будет. И в таком ракурсе распространенные ошибки нужно исключать. Поэтому если говорить о подобного рода разработках, то да. Никакого Си там быть не должно. Там нужна строго специализированная аппаратура и языки под неё. Но мы по-моему не крутимся в этой сфере. Почему постоянно оно приводится как пример? Что-то обилия разработчиков из самолетостроения в комментариях не наблюдается. Похоже, это у нашего брата просто «бамбалейо».

В C# тоже бенефиты, например память освобождать не надо. А как следствие сбурщик мусора требует процессорное время. И память освобождается дольше. И если тоже самое делать на С++, то результат себя лучше покажет, когда речь о высокой нагрузке. Вы не будете с этим спорить?

Нет, речь как раз о баге. Типичный пример, когда забыли проверить на нулл и разыменовали нулевой указатель. Или у вас такого не бывает?
Бывает. Когда я драйвер пишу, у меня DriverVerfier включен постоянно. Когда приложение, то memoryleakdetector прикомпоновываю. Все возможные инструменты проверки у меня работают постоянно. И я отлаживаю то что пишу, даже если в функции две строчки. И прорабатываю под отладчиком все возможные пути работы той или иной функции. А потом в комплексе все смотрю. Это не сложно. Обычная проверка того, что делаешь. Но, те о ком вы говорите, так не заморачиваются. Потому как им просто лень. Возникает вопрос, а зачем такой пассажир нужен? Как вы ранее упомянули, людей не поменяешь. Я, понимая это, по возможности буду избегать с такими встречи. И не буду входить в положение их тонкой и ленивой натуры.

Если человек не знает физику, то микробиологом ему не быть, потому что он основы не понимает.
А смена языка равна смене профессии? Языки высокого уровня, по сути ускорили разработку. Языки с «бенефитами» не только ускорили, но и ограничили. Поэтому и область применения у них разная.

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

Простите, но нет. Есть известный закон дырявых абстракций, который явно говорит, что достаточно знать +-1 уровень от своей текущей чтобы полноценно выполнять свою работу.
Скажите, а ассенизатор хорошо выполняет свою работу?

Кругозор — это полезно, никто не спорит.
Я говорил не о кругозоре, я говорил о профессионализме. Если вы умеете только что-то одно, вы не сможете решать более сложные задачи. Потому что не знаете ничего в смежных областях. А если и знаете то не факт что понимаете до конца, т.е. это уже опыт. А чтобы создать что-то реально новое, нужно знать очень много. Т.к. хорошие решения на самом деле, решаются не на одном уровне.

Но как уже сказано, знание «С++» никак не делает челвоека более хорошим разработчиком, чем знание C#.
Никак, согласен. Только, знание только С# тем более.
Почему постоянно оно приводится как пример? Что-то обилия разработчиков из самолетостроения в комментариях не наблюдается.

Окей, давайте не будем.


В C# тоже бенефиты, например память освобождать не надо. А как следствие сбурщик мусора требует процессорное время. И память освобождается дольше. И если тоже самое делать на С++, то результат себя лучше покажет, когда речь о высокой нагрузке. Вы не будете с этим спорить?

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


Бывает. Когда я драйвер пишу, у меня DriverVerfier включен постоянно. Когда приложение, то memoryleakdetector прикомпоновываю. Все возможные инструменты проверки у меня работают постоянно.

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


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

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


Скажите, а ассенизатор хорошо выполняет свою работу?

Наверное


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

В штатах есть такое понятие, как overqualified. Не встречали?


Никак, согласен.

Все равны


Только, знание только С# тем более.

Но некоторые равнее :)

Окей, давайте не будем.
Покорнейше благодарю.

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

Они работают на эвристиках, и проверяют реальное изменение.
Плохо работают? 99,9% ловят, еще на этапе разработки.

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

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

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

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

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

Лучше иметь компилятор, который отследит все случае, чем сидеть каждый раз руками с валгриндом и сравнивать.
Лучше, только никто еще этого не сделал. Для этого ему надо делать анализ кода, пока что и это плохо получается. И по факту, работать надо с тем что есть, а не мечтать о том, как было бы правильно. «Хочу чтобы было хорошо». Да я тоже хочу, дальше то что?

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

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

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

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

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

Но некоторые равнее :)
Я равнее, да.
Никогда не понимал тех, кому для признания в любви к языку А нужно ругать язык Б. Я люблю и C и Rust, но последний люблю за его возможности, а не за то, что в нем нельзя сделать трудно уловимые в C ошибки. Для меня это просто приятный бонус, за который приходится расплачиваться.
Я думаю имеется в виду, что контроль гораздо более полный и явный чем в управляемых языках
abondarev писал:
Автор языка Оберон Николаус Вирт, вложил идею внесения ограничений, что существенно уменьшает риск написания небезопасного ПО. При этом с помощью доработки компилятора автор доклада, предлагает создавать образы, нацеленные на различные задачи и платформы. Доклад был мне очень близок, поскольку мы в Embox пришли к похожим идеям по ограничениям.

Вы правы. Продуманные ограничения уменьшают риск написания небезопасного ПО.
Вспомним. Эдсгер Дейкстра ввел ограничение, указав на опасность goto.
Затем Бертран Мейер ввел ограничение, указав на опасность break и continue.

Развивая линию Дейкстры-Мейера, можно ввести дополнительные ограничения, указав на небезопасность служебных слов, организующих поток управления: goto, break, continue, if, then, else, case, of, switch, while, do, repeat, until, for, foreach, loop, exit, when, last и их аналогов.

Исходя из этих соображений, в визуальном языке ДРАКОН (во имя безопасности потока управления) исключены опасные служебные слова, организующие поток управления: goto, break, continue, if, then, else, case, of, switch, while, do, repeat, until, for, foreach, loop, exit, when, last и т.д. Вместо них используется математически строгая графика управления, которая реализует ту же самую функцию, что и перечисленные служебные слова.

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

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

Таким образом, при использовании ДРАКОНа (при описании потока управления) остаются лишь опечатки и ошибки, появляющиеся на ЛИНЕЙНЫХ участках программ. Однако такие ошибки можно сравнительно легко выявить и устранить.

bit.ly/2Mlg4Ou
bit.ly/1UQ4zuU
habr.com/ru/post/345320
drakonhub.com/files/pe_drakon_automata_mitkin_2019.pdf

С уважением,
Владимир Данилович Паронджанов
Mobile: +7-916-111-91-57
Viber: +7-916-111-91-57
E-mail: vdp2007@bk.ru
Skype: vdp2007@bk.ru
Website: drakon.su
Webforum: forum.drakon.su
Да, про Дейкстру и Мейера тоже было в контексте Оберона. А в кулуарах даже рассуждали об использовании графических языков в АСУ для АЭС. Но лично мое мнение, что графические языки имеют достаточно узкую сферу применения. Для определенных задач они действительно хороши, но например для написания ядра ОС, точно не подходят.
UFO just landed and posted this here
Автор доклада является главным конструктором SCADA СУОК для АЭС
Разговор был с автором доклада, у которого есть реальные внедрения.

SCADA обычно состоит из минимум двух частей, РМО (рабочее место оператора) там используются мнемограммы, и рантайм управления. Вот рантайм может быть как на графических языках (Стандарт МЭК 61131-3 ), так и не на графических например на Обероне. Об этом можно например на хабре посмотреть тут

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


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


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


Исходя из этих соображений, в визуальном языке ДРАКОН (во имя безопасности потока управления) исключены опасные служебные слова, организующие поток управления: goto, break, continue, if, then, else, case, of, switch, while, do, repeat, until, for, foreach, loop, exit, when, last и т.д.

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


PS нет смысла писать контактные данные под каждым комментарием — для них существует профиль пользователя

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

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

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

Надеюсь, это был сарказм.

Это решаемая задача. И да, очень нужная — которую надо закладывать в инструментарий при его проектировании.
Сейчас проекты экспортируются в текстовый/Иксмл формат и могут сравниваться.
В принципе, я читаю например Роквелловские или Сименса текстовые диффы для релейки.

Но в целом потому говорю, что нужно закладывать при проектировании — визуальному языку нужен и визуальный дифф.
Ох-ох, личный опыт с парой визуальных инструментов с xml-бэкендом и парой основанных на xml «языках» программирования терзает мою душу смутными сомнениями…

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


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

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

Относительно комментариев вроде:
Функция заработала сразу! Более того, при переносе алгоритма в дракон-схему, я обнаружил, что у меня в ней была ошибка!
А может, прошло время, и у человека в голове к моменту переноса все уложилось по полкам? А язык оказался не причем? Т.е. это было совпадение. Один случай на мой взгляд ничего не доказывает. Нужно вести статистику и из неё вычислять среднее значение.

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

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

Цитату Сергея Ефанова я взял из его статьи «Программирование микроконтроллеров на ДРАКОНе».
Возможно, вы измените мнение, если прочитаете статью
Чтобы изменить мнение, нужно год-два этим заниматься. Мое мнение статьи не меняют. Особенно когда я не являюсь специалистом в области. А там где являюсь — нет надобности читать.
Сергей Ефанов поясняет:
...

Рад за Сергея, но все ещё не понимаю пользу Дракона для нормальных программистов.


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

Пустой набор слов, которые вместе ничего не обозначают.


на основе визуального логического исчисления

Не слышал о таком.

mayorovp писал:
Не слышал о таком.

Я описал «визуальное логическое исчисление» в журнале «Программирование» в 1995 г. («Графический синтаксис языка ДРАКОН») и в ряде книг (см. мой профиль).
Это теоретическая основа языка ДРАКОН.

Профессор А.Н. Степанов в «Курсе информатики для студентов информационно-математических специальностей» (2018) отмечает:
«Обсуждаемый подход… был развит в процессе создания отечественного графического языка программирования ДРАКОН… Чтобы получить полноценный язык программирования, необходимо было создать математически строгий метод формализации… Для решения этой задачи был разработан специальный математический аппарат — визуальное логическое исчисление иконок, который стал теоретической основой языка ДРАКОН… Язык двумерного структурного программирования ДРАКОН является полным по Тьюрингу и относится к универсальным языкам программирования… Написание программы становится более понятным и удобным для человека, повышается производительность труда программистов» [15, pp. 1017-1019].

В таком случае, вы крайне неудачно выбрали термин.


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


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

Обычное словоблудие для прикрытия докторских работ итп.

Если не ошибаюсь поверхностным взглядом, это обычная (хорошо, еще если — потому что я не заметил в роликах нормальной реализации переходов FSA) реализация ru.wikipedia.org/wiki/IEC_61131-3 SFC

Впрочем, за приоритет можно поспорить, но я сталкивался с реализацией от Сименса лет 15-20 назад.
Ведь если посмотреть глубже, то даже в уже упомянутой дискуссии по поводу устаревания языка Си подразумевалось, что данный язык небезопасен и с его помощью очень просто “выстрелить себе в ногу”.
Ну если на примере, то язык Си, изначально, не имеет представления о том, что такое стек. В контексте упомянутого ранее STACKLEAK, скорее виновата архитектура процессоров и трансляторы под них.

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

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

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

Я другой пример приведу, в процессорах Itanium стек данных и стек вызова развязан. А в будущем поколении процессоров Intel будет shadow stack. Что автоматически защищает от buffer overrun. Имеет ли язык Си к этому отношение? Что будет со стороны ОС сделано чтобы оно заработало? Надо ли будет дорабатывать компиляторы? По всем вопросам однозначно нет. А если так, возникает вопрос, как это получается, что появление аппаратного механизма делает абстрактный язык Си — безопаснее?

Наверное у нас изначально разница в терминах. А значит и говорить не о чем.
А значит и говорить не о чем.

Ну зачем Вы пишите, если говорить не о чем?

Что будет со стороны ОС сделано чтобы оно заработало? Надо ли будет дорабатывать компиляторы? По всем вопросам однозначно нет.

По этим двум вопросам однозначно, да!
Вот мы тут портировали Embox под Эльбрус. Embox это ОС и там пришлось работу со стеком (при переключении контекстов) сильно замысловатым делать. Ну и конечно, как работать со стеком для конкретной архитектуры (и даже конкретного ABI) компилятор должен знать.

По поводу синтаксиса языка Си в привязке к стеку. Вообще то все языки программирования неявно имеют представление об управлении памяти, и базовыми являются всего три конктрукции: выделение памяти на стеке, выделение памяти в куче, и глобальные переменные. Часть языков, вообще запретили всякие глобальные переменные, и оставили только стек и кучу.

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

По этим двум вопросам однозначно, да!
Со стороны ОС поддержать новый процессор. И делается это на языке Си который не знает ничего об этом. Компиляторы дорабатывать не надо. Ибо они не будут напрямую работать с shadow stack, учитывая его архитектуру.

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

Embox это ОС и там пришлось работу со стеком (при переключении контекстов) сильно замысловатым делать.
А что вам мешало использовать встроенные средства языка Си для переключения контекста? Мы ведь уже выяснили что язык Си связан с термином стек.

(и даже конкретного ABI)
Нонсенс. Как получается что на MSVC я под Linux бинари собираю?

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

А если так, возникает вопрос, как это получается, что появление аппаратного механизма делает абстрактный язык Си — безопаснее?
Вы лучше на этот вопрос ответьте. Как я уже сказал, по двум пунктам из трех — однозначно нет. Пояснения выше. Один пункт, это поддержка процессора. Но не языком и даже не его компилятором. Ваш опыт портирования ровным счетом ничего не доказывает.
А что вам мешало использовать встроенные средства языка Си для переключения контекста?
Это какие? Лучше ссылочкой на пункт стандарта.
Коллега, это была ирония. Мне казалось, что в моих утверждениях видно какого мнения я придерживаюсь.
Очень просто: студия при сборке бинарей под Linux использует gcc либо clang вместо родного cl.exe. Потому что cl.exe, внезапно, совсем не умеет создавать бинарники под linux, даже если там такой же amd64 что и на винде...
mayorovp Я это сделаю и при помощи cl.exe. И делал уже ранее. До того как все упомянутое вами появилось. А то что clang может генерировать под Windows, Android и так далее, ни на какие мысли не наталкивает?

Вот именно, Вам казалось!
Да? А может кое-кто просто печатного текста не понимает? И не может сопоставить что собеседник говорил до, и говорит сейчас?

Вам не кажется, что компилятор (бэкенд) должен быть доработан.
Мне не кажется, я знаю что не должен быть. А раз вам кажется, расскажите что и как должно быть доработано. Конкретно на пальцах, а не на уровне идеи. Я же говорю что не надо. Учитывая как работает shadow stack. Один раз включаем его на процессоре и все. Грубо говоря. Механизм спроектирован обратно совместимо.

Поскольку если архитектурной поддержки не требуется
Я такое утверждал? Более того, в контексте утверждения, не понятно о чем оно вообще. Чуть ниже объясняю.

почему не компилируется например под ARM с помощью gcc на x86
Встречное? почему на MSVC x86 компилируется и под ARM и под ARM64 и под x64?

Для чего вообще компилятору указывается ABI?
Компилятор так спроектирован. MSVC например, на, как вы говорите, ABI не завязан. Максимум instrinsic функции, которые реализует программист. Но сделано это для интеграции с операционной системой. Таких моментов не много. Только я подчеркну. Это все расширения языка. Расширения делает разработчик компилятора. И к стандарту оно отношения не имеет. Было время когда и расширений не было. Сделали их для удобства разработки для конкретных архитектур. И оно снова не имеет отношения к стандарту. Если в gcc этого не заложили, и вы на этом основании делаете выводы, то извините, проблема ваша.

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

Изначально претензия была к формулировке, о том что язык ничего не знает про стек.
Еще раз, укажите место в стандарте Си, где явно упомянута сущность стека. И если упомянута, то в каком контексте. Расскажите про встроенные функции языка для работы со стеком. Расскажите про встроенные функции для управления памятью. Из стандарта только. На язык.

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

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

надеясь на наличие мозгов у собеседника
Тебя прямым текстом послать? Или неявно? Хочешь мозгами померятся, пиши в личку. Посмотрим…
Я это сделаю и при помощи cl.exe

Нельзя ли почитать об этом подробнее?

Увы, нет. Дело было давно, лет 7 назад и делал я это самостоятельно. Что забавно, возникла такая потребность примерно в таком же контексте. Это был спор. Я потратил неделю и сгенерированный код cl.exe компилятором я заставил работать на Linux. Написал утилиту. Нужно было преобразовать PE в ELF. Ну и куча чего по мелочи. Делал на базе х86. Для х64 заморочек больше, например нужно согласовать модель вызова. Преобразовал все и заработало. Т.е. имеем сам факт, что код сгенерированный компилятором от студии, нормально работает и в Linux.

За выигранный спор, мне ничего не вернули. :) Объяснено это было тем что преобразование не считается. Все хотели из коробки. О чем я заранее предупредил, как я буду делать. И на момент посвящения в мои действия, у них не было никаких вопросов и возражений. Но когда появился результат…

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

Собственно примерно как сейчас, с другим собеседником.
А зачем отвечаете?

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

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

Вам не кажется, что компилятор (бэкенд) должен быть доработан. Поскольку если архитектурной поддержки не требуется, почему не компилируется например под ARM с помощью gcc на x86? Для чего вообще компилятору указывается ABI?

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

А если так, возникает вопрос, как это получается, что появление аппаратного механизма делает абстрактный язык Си — безопаснее

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

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

Нонсенс. Как получается что на MSVC я под Linux бинари собираю?

Очень просто: студия при сборке бинарей под Linux использует gcc либо clang вместо родного cl.exe. Потому что cl.exe, внезапно, совсем не умеет создавать бинарники под linux, даже если там такой же amd64 что и на винде...

UFO just landed and posted this here
Конечно. Правда нужно еще хранить где то указатели на стекфреймы, но это мелочи.
Я имел в виду, что есть разница в реальных компиляторах ( про которые не стоит забывать) при реализации: глобальных переменных, локальных переменных, статических локальных переменных, переменных выделенных на куче.
А так, конечно согласен, стек (и отсюда почему большинство языков реализуют именно такую структуру) это только очень удобная реализация конкреной идеи распределения переменных и регистров. Но так как компилятор должен знать как устроена организация его локальных переменных, то я и написал, что это преувеличение.
Правда нужно еще хранить где то указатели на стекфреймы
Первый элемент в выделенной куче — указатель на предыдущий фрэйм. Остальное локальные переменные.

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

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

То никакого треша в комментах конечно бы не было!
А так он понес прекрасную фигню, что компилятор не должен ничего знать об архитектуре процессора… Надеюсь он имел в виду, что используется промежуточный код типа llvm, но без этих пояснений, выглядит странно.
И, если бы автор оригинального коммента, написал, как Вы
Этому есть название — подлизаться. Вроде ген. дир. А тут такое…

А так он понес прекрасную фигню, что компилятор не должен ничего знать об архитектуре процессора…
А что? Разве должен? Блин, а я не знал. Спасибо что просветили.

Надеюсь он имел в виду, что используется промежуточный код типа llvm
А че такое промежуточный код?
Мы пишем драйвер на C++ (внезапно, даже 17). Да, у нас нет стандартной библиотеки, но тупо из-за наличия деструкторов в языке и инкапсуляции — разработка упрощается на порядки, никакие ресурсы не текут. Я не вижу смысла писать на чистом С вообще в любой разработке — даже крошечный сабсет С++98 выигрывает у чистого С по всем возможным статам (ну, кроме вероятного отсутствия компилятора под какой-нибудь некроконтроллер).
Ну про С++98 это перебор — на нем очень неудобно писать с STL (а без нее опять сырые указатели итп), а вот с++11/14 +линтер уже вполне безопасен и удобен по сравнению с другими условно безопасными языками.

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

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

Впрочем последние две темы настолько тонкие, что в большинстве языков до обсуждения такого дело и не доходит — есть проблемы покрупнее =)
В конкретно моем случае (полное отсутствие стандартной библиотеки в кернеле) — мы написали свои строки\умные указатели и тд и тп.
Речь шла о замене С/С++.
С++ не используется в надежном ПО, не потому что нет компиляторов, а потому что менее предсказуемо, и можно уйти в область, смотри как я могу. Берем например стандарт MISRA. там вводятся различного рода ограничения на сложные конструкции. Программировать безусловно становиться тяжелее, но вот код более поддерживаемый и понятный, следовательно надежный.
Вот Вам пришлось написать стандартную библиотеку (или какие то ее части), а кто сказал что там нет ошибок? Анализаторы кода стаонвятся сложнее, если использовать хитурые конструкции и так далее. А так да, на чем писать дело вкуса, и 17 плюсы (да и не только 17) конечно добавляют возможностей для разработчика по сравнению с чистым Си.
abondarev затронул важную проблему. Существует потребность в безопасных языках. Язык ДРАКОН — попытка создать безопасный визуальный язык.

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

Цель языка ДРАКОН — обеспечить безопасность потока управления.

anatolymik писал:
Вообще странное утверждение. Из которого следует чем сложнее алгоритм тем легче в нем ошибиться, потому что текста много. Можно подумать на драконе ничего для описания этого же алгоритма делать не надо будет. Ну будут у вас не такие ошибки как на классических языках. Будут другие. Разница то в чем?

Разница в том, что на ДРАКОНе ошибок будет меньше или не будет совсем.
Сергей Ефанов поясняет:
Переписал на ДРАКОНе довольно запутанную функцию из реального проекта.

Функция заработала сразу! Более того, при переносе алгоритма в дракон-схему, я обнаружил, что у меня в ней была ошибка! Эта функция работала уже довольно давно, не в одной сотне изделий. Ошибка не была фатальной, она возникала редко, и компенсировалась переподключением к серверу. Но она была!

В тексте на Си её было незаметно. А при попытке перенести алгоритм на дракон-схему, ошибка стала не просто заметной — алгоритм в этом месте «не вырисовывался»!

anatolymik писал:
Ну не записали вы их вручную. Ну автоматически будет сгенерировано. Сгенерировано будет все равно исходя из того что вы задали на входе. А если вы на входе зададите неправильно, что ветвления правильными вдруг станут?

Вероятность того, что вы на входе (т.е. в дракон-схеме) зададите неправильно, очень мала. потому что ДРАКОН срывает с ошибок «шапку-невидимку». Ошибки «сами лезут в глаза», поэтому пользователь (с большой вероятностью) их не сделает. На это есть две причины.

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

2) Графика дракон-схемы формируется программой дракон-конструктор, на основе визуального логического исчисления по правилам визуального логического вывода.

Это значит, что (во избежание ошибок) пользователю языка ДРАКОН запрещено проводить линии между иконами дракон-схемы. Все линии автоматически проводит дракон-конструктор, а пользователь лишь управляет этим процессом, указывая какую икону (или макроикону) выбрать и в какую валентную точку ее вставить. Это вкратце.

Разумеется, записывая текст внутри иконы, пользователь может ошибиться, но это будет ошибка ЛИНЕЙНОГО участка, которую сравнительно легко можно выявить и устранить.
Очень интересная форма высказывания. Сначала вы написали этот комментарий выше, потом удалили. Сейчас написали все тоже самое что было там. Вряд ли так можно заинтересовать.
Это старинная известная технология.

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

В Java это, к примеру — Eclipse Modeling Framework (EMF) (Не взлетел, но кто-то юзает).

image
Преимущество C — наличие формальной семантики и тулзов для кодогенерации и верификации. Для Rust формальная семантика еще не закончена, для C++ она врядли возможна (слишком сложный язык), для ATS ей некому заниматься. А больше языков, хорошо подходящих для низкоуровневого программирования толком и нет.
На ваш взгляд Rust еще молодой слишком?
С верификацией у Си не очень то хорошо, по крайней мере по сравнению с функциональными языками. Почему тогда они не вытесняют Си в тех местах где нужна верификация?
Как язык он вполне зрелый и там, где возможно, лучше использовать его вместо C/C++. Но в проектах, где требуется сертификация, пока такой возможности, к сожалению, нет. Может быть появится.
Простой вопрос: как скопировать дистрибутив rust на флешку?
Именно если он из себя такой весь системный то почему сам так хреново сделан.
Даже если просто если сравнить c Tiny C Compiler который не такой молодёжный и безопасный, но выглядит на порядок лучше.
UFO just landed and posted this here
Разработчики KasperskyOS так и делают — начали с Ivory, потом перешли на что-то самописное. Аргументировани тем, что сгенерированный код на C потом сертифицируют для госструктур.