Там вроде только OSD переписали — то есть собственно демон который висит над диском и шурудит секторами, по одному демону на диск, а остальное осталось как есть; да и Magic Pocket там важная, но не самая объёмная часть инфраструктуры. То есть да, в целом дело хорошее и вселяет надежду (я уже джва году жду не дождусь возможности попробовать Rust в embedded продакшне), но я не уверен, что это большая веха для Rust. Скорее просто ещё одно напоминание о том что такие вещи вообще не стоит писать на garbage collected языках.
А точно был мальчик? Потому что я тоже эту публикацию помню, а потом вроде бы оказалось что там журналистов учёные насиловали как могли, и на самом деле Dropbox переписал на Rust только пару мелких служб в которых у них затык по производительности был, а всё остальное как было на Go так и есть.
function show_author(name) {
user = get_user(name)
if ok?(user) {
show(user)
} else {
log("Something wrong with " + user)
show(ADMIN)
}
}
Спасибо что исправили, но я всё ещё не вижу, что этот пример показывает. Если вы подразумеваете, что возможность передать в show_author() не строку а Null (то есть всё-таки имеете в виду статическую а не сильную типизацию) экономит вам время на обработку ошибок, то, во-первых, вы игнорируете другие методы обработки ошибок...
// name типизировано и всё-таки компилируется - поздравляю вас гражданин соврамши.
void show_author(std::string name) { // Строка может быть пустой.
auto user = get_user(name); // Проверяет name.empty().
… делаете предположение, что надо изобретать собственный тип...
// Опять типизировано и опять компилируется - дважды соврамши.
void show_author(std::optional<std::string> name) { // Из стандартной библиотеки.
… неконсистентны в том, где вы обрабатываете ошибки; user проверили перед передачей в show() но предполагаете, что show_author() может получить аргумент без проверки; ну и наконец умалчиваете о том, что в вашем варианте вам ещё потребуется написать тест, который вам покажет что ваша нетипизированная show_author() (а заодно и get_user(), потому что контроля типов и там нет) не взрывается при передаче не только строки или Null, но и какого-то другого типа.
В общем, что не компилируется — не показано (на самом деле компилируется). Что быстрее бы в продакшн ушло — тоже не показано (вы не упоминаете время на компенсацию возросших рисков). Я понимаю, что писать корректные примеры (и даже корректный код) ниже людей с критическим складом ума, но хотелось бы поменьше статей в которых сильная типизация путается со статической, треть кода формально некорректна и вдобавок ничего не иллюстрирует, а ещё одна треть опровергается в одно предложение.
Я прошу вас поправить некорректный псевдокод, в котором откуда-то магически возникают переменные (а использование других переменных бессмысленно — вы вызываете get_name() чтобы получить, внезапно, уже имеющееся name).
Похоже на то… chapuza, какие-то комментарии будут? Код в статье некорректный (а это, если что, треть всего кода в статье), хочется увидеть корректный и понять, как он иллюстрирует недостатки сильной типизации.
Я имел в виду то, что непонятно, по какой причине — как автор утверждает — не скомпилируется код с сильными типами (если автор вообще имел в виду сильные типы а не статические — я не могу додумать правильный пример за него). С сильными vs. слабыми я даже не могу придумать вариант — код выше не делает никакого преобразования типов. Если же автор имел в виду static vs. dynamic, что-то вроде name = get_user(user); if name != Null ..., подразумевая что со статическими типами мы не можем вернуть Null вместо строки и вынуждены изобретать variant type (подозреваю что это, судя по "… изобрести новый монадический тип для возможно указанного автора"), то получается уже совсем другой код, в котором get_user() сознательно написана без возможности вернуть ошибку (кодом возврата с передачей name через аргумент / пустой строкой / исключением и т.п.).
function show_author(name) {
if get_user(name) {
show(name)
} else {
log("Something wrong with " + user)
show(ADMIN)
}
}
Кстати, не затруднит поправить этот код? Я просто не вижу, откуда взялся user — наверное, имелось в виду show_author(user) и дальше get_user(user) вместо get_user(name)? Потому что это влияет на суть примера — ошибку-то вы вроде проверяете. :) Пример не показывает, почему код бы не скомпилировался с сильными типами.
Почему бы нет? Дополнительных усилий там будет не так уж много (при парсинге другому типу присвоите, да и сам тип будет алиасом в одну строку — если уж утрировать), а если вы потом много где жонглируете этими реквизитами, то может и окупиться по времени, тем более если, как в примере, оно у вас в противном случае будет вызывать падения в рантайме.
Мне кажтся, что в этом проблема статьи — она как раз демонстрирует задачи, лучше решаемые тестами. Алгоритмические ошибки — всё-таки не про типизацию.
Ну и опять же, есть спорные места, выше уже написали — если передавать имя пользователя в строке, то да, тип не распознает передачу фамилии вместо имени, а вот если имя и фамилию сделать разными типами, то вполне себе решение.
Похожи немного, да; ключевая разница — они с реализациями подмешиваются, так что мы сразу даём классу дополнительное обобщённое поведение (а не обязуемся новое специализированное поведение в классе реализовать). Взять в пример тот же Drawable — он может притащить с собой члены данных с графикой (которую мы можем назначить для каждого экземпляра свою) и код для отрисовки, а код класса к которому подмешиваем останется нетронут и даже не узнает, что класс внезапно научился себя отображать.
Множественное наследование тянет за собой diamond problem, так что от него уже все шугаются. Плюс не всегда нужна семантика is-a, миксины хорошо ложатся на текущий курс партии — composition over inheritance.
Когда полезно иметь данные в миксине — например в геймдеве. Если хочется чтобы объект имел свойства 'Serializable', 'Drawable', 'InventoryOwning' и 'Killable' (и ещё много чего), то реализовывать через множественное наследование — разлапистая иерархия получается, и изменять потом сложно. Легче набрать объект из миксинов, тем более что тесное взаимодействие с основным классом будет наоборот вредить гибкости.
И сколько бы не говорили, что деньги — не главное, именно они являются мерилом успеха в современном обществе. Счастье на них не купишь, а вот новые возможности и определенную свободу вполне. За этим и едут. <...> Но в любом случае российские зарплаты пока не дотягивают до европейских.
Есть ли выход? <...> Как удержать ценного разработчика?
… и дальше про молодёжную политику, про повышение квалификации, про интересные задачи и работу над интересным проектом в дружной команде, про всё что угодно кроме, собственно, конкурентных зарплат. Чего вы только не придумаете, Штирлиц, чтобы не ехать на картошку. :) Давайте статью переименуем в "1001 способ удержать разработчика без повышения зарплаты".
Этим раньше занималось централизованно 22 ЦНИИ МО, мы с ним как-то работали, потом функции распределили. Но да, на закладки проверяют, и даже сами разработчики которые их применяют тоже делают проверки (скажем, ставят в безэховую камеру для проверок на посторонние ЭМ эмиссии чтобы добро от военпредов получить). Ну и списки доступных для применения комплектующих держат.
Наверное, есть исключения — или долгоиграющие AAA проекты (кхе-кхе, на тебя смотрю, Star Citizen), или всякие MMO/MOBA у которых очень долгий цикл сопровождения. Но да, для проектов поменьше, для инди, выкатить рабочее важнее внутренних красот.
Ну так это из блога Unity, понятно что там DOTS будет. :)
Хотя вообще, я бы не сказал что это такая уж плохая вещь. Во всяком случае ECS как идея, даже если не принимать в расчёт выгоды с точки зрения производительности.
Может быть, стоит посмотреть на участок, где создаются объекты производных классов? Это не критика, я верю что вы дотошно всё рассмотрели, так что это мысли вслух; я пробовал, и неиспользованные виртуальные функции GCC с -flto удалять может, но спугнуть его может что угодно — скажем, если заключить создание объекта производного класса в if то, даже если там выше константа и можно этот if выбросить в ходе оптимизации, то всё равно откажется верить что никаких других конкретных классов из этой иерархии не создаётся.
С другой стороны, полагаться на труднопредсказуемые оптимизации тоже, конечно, нехорошо. Вообще, если получается очень развесистый API с кучей виртуальных функций и потом возникает мысль, что многие из них не используются и реализованы только потому что в базовом классе они чисто виртуальные — то, может быть, этот API слишком много одеяла на себя тянет.
Вот — у вас самих проект на 19к LoC, а говорите что не до тысяч строк. :) В моём примере это медицина была, там много всего на борту, тот же offline анализ данных.
Понятно что на C тоже можно делать очень крупные проекты для МК. Просто на C++ это быстрее писать, часто легче читать и поддерживать, и, если знать что обходить стороной, то практически забесплатно.
Embedded сильно разный везде бывает, у всех своя специфика, для каких-то орехов как раз впору. :) И мегабайт для этого тоже не нужен. Вот из своей практики пример — количество in-house кода подбирается к двадцати тысячам строк (в основном C++, немного C, немного ассемблера в узких местах), если весь библиотечный код посчитать (а библиотек там порядком) то почти полмиллиона строк кода. И это компилируется для машинки с 256к флэша (точнее 192к, остальное отведено на загрузчик с обновлением по воздуху) и 32к оперативной памяти.
Когда проект из крупных, C++ очень сильно помогает. Понятно что если с оглядкой использовать — некоторые фичи накладно тащить на контроллер, а другие — сплошной профит с любой стороны.
Там вроде только OSD переписали — то есть собственно демон который висит над диском и шурудит секторами, по одному демону на диск, а остальное осталось как есть; да и Magic Pocket там важная, но не самая объёмная часть инфраструктуры. То есть да, в целом дело хорошее и вселяет надежду (я
уже джва годужду не дождусь возможности попробовать Rust в embedded продакшне), но я не уверен, что это большая веха для Rust. Скорее просто ещё одно напоминание о том что такие вещи вообще не стоит писать на garbage collected языках.А точно был мальчик? Потому что я тоже эту публикацию помню, а потом вроде бы оказалось что там журналистов учёные насиловали как могли, и на самом деле Dropbox переписал на Rust только пару мелких служб в которых у них затык по производительности был, а всё остальное как было на Go так и есть.
Спасибо что исправили, но я всё ещё не вижу, что этот пример показывает. Если вы подразумеваете, что возможность передать в
show_author()
не строку а Null (то есть всё-таки имеете в виду статическую а не сильную типизацию) экономит вам время на обработку ошибок, то, во-первых, вы игнорируете другие методы обработки ошибок...… делаете предположение, что надо изобретать собственный тип...
… неконсистентны в том, где вы обрабатываете ошибки;
user
проверили перед передачей вshow()
но предполагаете, чтоshow_author()
может получить аргумент без проверки; ну и наконец умалчиваете о том, что в вашем варианте вам ещё потребуется написать тест, который вам покажет что ваша нетипизированнаяshow_author()
(а заодно иget_user()
, потому что контроля типов и там нет) не взрывается при передаче не только строки или Null, но и какого-то другого типа.В общем, что не компилируется — не показано (на самом деле компилируется). Что быстрее бы в продакшн ушло — тоже не показано (вы не упоминаете время на компенсацию возросших рисков). Я понимаю, что писать корректные примеры (и даже корректный код) ниже людей с критическим складом ума, но хотелось бы поменьше статей в которых сильная типизация путается со статической, треть кода формально некорректна и вдобавок ничего не иллюстрирует, а ещё одна треть опровергается в одно предложение.
Я прошу вас поправить некорректный псевдокод, в котором откуда-то магически возникают переменные (а использование других переменных бессмысленно — вы вызываете get_name() чтобы получить, внезапно, уже имеющееся name).
Похоже на то… chapuza, какие-то комментарии будут? Код в статье некорректный (а это, если что, треть всего кода в статье), хочется увидеть корректный и понять, как он иллюстрирует недостатки сильной типизации.
Я имел в виду то, что непонятно, по какой причине — как автор утверждает — не скомпилируется код с сильными типами (если автор вообще имел в виду сильные типы а не статические — я не могу додумать правильный пример за него). С сильными vs. слабыми я даже не могу придумать вариант — код выше не делает никакого преобразования типов. Если же автор имел в виду static vs. dynamic, что-то вроде
name = get_user(user); if name != Null ...
, подразумевая что со статическими типами мы не можем вернуть Null вместо строки и вынуждены изобретать variant type (подозреваю что это, судя по "… изобрести новый монадический тип для возможно указанного автора"), то получается уже совсем другой код, в которомget_user()
сознательно написана без возможности вернуть ошибку (кодом возврата с передачей name через аргумент / пустой строкой / исключением и т.п.).Кстати, не затруднит поправить этот код? Я просто не вижу, откуда взялся
user
— наверное, имелось в видуshow_author(user)
и дальшеget_user(user)
вместоget_user(name)
? Потому что это влияет на суть примера — ошибку-то вы вроде проверяете. :) Пример не показывает, почему код бы не скомпилировался с сильными типами.Почему бы нет? Дополнительных усилий там будет не так уж много (при парсинге другому типу присвоите, да и сам тип будет алиасом в одну строку — если уж утрировать), а если вы потом много где жонглируете этими реквизитами, то может и окупиться по времени, тем более если, как в примере, оно у вас в противном случае будет вызывать падения в рантайме.
Мне кажтся, что в этом проблема статьи — она как раз демонстрирует задачи, лучше решаемые тестами. Алгоритмические ошибки — всё-таки не про типизацию.
Ну и опять же, есть спорные места, выше уже написали — если передавать имя пользователя в строке, то да, тип не распознает передачу фамилии вместо имени, а вот если имя и фамилию сделать разными типами, то вполне себе решение.
Похожи немного, да; ключевая разница — они с реализациями подмешиваются, так что мы сразу даём классу дополнительное обобщённое поведение (а не обязуемся новое специализированное поведение в классе реализовать). Взять в пример тот же Drawable — он может притащить с собой члены данных с графикой (которую мы можем назначить для каждого экземпляра свою) и код для отрисовки, а код класса к которому подмешиваем останется нетронут и даже не узнает, что класс внезапно научился себя отображать.
Множественное наследование тянет за собой diamond problem, так что от него уже все шугаются. Плюс не всегда нужна семантика is-a, миксины хорошо ложатся на текущий курс партии — composition over inheritance.
Когда полезно иметь данные в миксине — например в геймдеве. Если хочется чтобы объект имел свойства 'Serializable', 'Drawable', 'InventoryOwning' и 'Killable' (и ещё много чего), то реализовывать через множественное наследование — разлапистая иерархия получается, и изменять потом сложно. Легче набрать объект из миксинов, тем более что тесное взаимодействие с основным классом будет наоборот вредить гибкости.
Меня вот что в статье удивило...
… и дальше про молодёжную политику, про повышение квалификации, про интересные задачи
и работу над интересным проектом в дружной команде, про всё что угодно кроме, собственно, конкурентных зарплат. Чего вы только не придумаете, Штирлиц, чтобы не ехать на картошку. :) Давайте статью переименуем в "1001 способ удержать разработчика без повышения зарплаты".Этим раньше занималось централизованно 22 ЦНИИ МО, мы с ним как-то работали, потом функции распределили. Но да, на закладки проверяют, и даже сами разработчики которые их применяют тоже делают проверки (скажем, ставят в безэховую камеру для проверок на посторонние ЭМ эмиссии чтобы добро от военпредов получить). Ну и списки доступных для применения комплектующих держат.
Наверное, есть исключения — или долгоиграющие AAA проекты (кхе-кхе, на тебя смотрю, Star Citizen), или всякие MMO/MOBA у которых очень долгий цикл сопровождения. Но да, для проектов поменьше, для инди, выкатить рабочее важнее внутренних красот.
Ну так это из блога Unity, понятно что там DOTS будет. :)
Хотя вообще, я бы не сказал что это такая уж плохая вещь. Во всяком случае ECS как идея, даже если не принимать в расчёт выгоды с точки зрения производительности.
Может быть, стоит посмотреть на участок, где создаются объекты производных классов? Это не критика, я верю что вы дотошно всё рассмотрели, так что это мысли вслух; я пробовал, и неиспользованные виртуальные функции GCC с
-flto
удалять может, но спугнуть его может что угодно — скажем, если заключить создание объекта производного класса в if то, даже если там выше константа и можно этот if выбросить в ходе оптимизации, то всё равно откажется верить что никаких других конкретных классов из этой иерархии не создаётся.С другой стороны, полагаться на труднопредсказуемые оптимизации тоже, конечно, нехорошо. Вообще, если получается очень развесистый API с кучей виртуальных функций и потом возникает мысль, что многие из них не используются и реализованы только потому что в базовом классе они чисто виртуальные — то, может быть, этот API слишком много одеяла на себя тянет.
Вот — у вас самих проект на 19к LoC, а говорите что не до тысяч строк. :) В моём примере это медицина была, там много всего на борту, тот же offline анализ данных.
Понятно что на C тоже можно делать очень крупные проекты для МК. Просто на C++ это быстрее писать, часто легче читать и поддерживать, и, если знать что обходить стороной, то практически забесплатно.
Embedded сильно разный везде бывает, у всех своя специфика, для каких-то орехов как раз впору. :) И мегабайт для этого тоже не нужен. Вот из своей практики пример — количество in-house кода подбирается к двадцати тысячам строк (в основном C++, немного C, немного ассемблера в узких местах), если весь библиотечный код посчитать (а библиотек там порядком) то почти полмиллиона строк кода. И это компилируется для машинки с 256к флэша (точнее 192к, остальное отведено на загрузчик с обновлением по воздуху) и 32к оперативной памяти.
Когда проект из крупных, C++ очень сильно помогает. Понятно что если с оглядкой использовать — некоторые фичи накладно тащить на контроллер, а другие — сплошной профит с любой стороны.
Микроконтроллеры и задачи разные бывают, подчас на десятки и сотни тысяч строк кода счёт идёт.
А вы с
-flto
проверили? Или просто в статье не упомянуто? Я ещё раз с испугу перечитал, вдруг, думаю, в первый раз проглядел. :)