
Компания Microsoft развивает новый язык программирования на основе Rust. Как пишет издание ZDnet, проект получил название Verona. Планируется, что на его основе Microsoft перепишет некоторые компоненты Windows 10, чтобы решить проблемы с безопасностью.
Как указывает ZDnet со ссылкой на Мэтта Миллера, специалиста Microsoft по безопасности, около 70% всех уязвимостей, которые были обнаружены в продуктах Microsoft в последние годы, были связаны с ошибками управления памятью. Это происходит потому, что языки C и C++, которые традиционно используют для создания системного ПО, передают управление оперативной памятью разработчику. Это неизбежно приводит к ошибкам.
Новый язык Microsoft на базе Rust должен, в отличие от C и C++, реализовывать механизм автоматического управления памятью. Отличие нового языка от Rust заключается в применении концепции владения не единичными объектами, а группами объектов. Репозиторий проекта уже опубликован на Github.
Rust был разработан в 2006 году Грейдоном Хоаром, работавшим в Mozilla. Через три года Mozilla начала вкладывать деньги в развитие Rust и расширила команду по его разработке. Заинтересованность Mozilla в Rust была связана, как пишет ZDnet, с большим числом критических уязвимостей в браузере Firefox — более 4 млн строк браузера было написано на C++.
В августе 2019 года Джош Триплетт, ведущий инженер Intel, сообщил о том, что Intel заинтересована в том, чтобы впоследствии Rust стал равноценен языку C. Кроме Mozilla и Microsoft, языком Rust пользуются в Google, Dropbox, Facebook, Amazon, Fastly и других компаниях.
Комментарии (77)
slonopotamus
08.12.2019 14:01+1Репозиторий проекта уже опубликован на Github.
Кхм. Но там ничего нет кроме файла лицензии.
abrwalk
08.12.2019 14:38Тоже самое и с другой «уникальной разработкой» github.com/MicrosoftEdge/MSEdge
MrSmith33
08.12.2019 14:19Вот доклад про этот язык: Digital Security by Design: Security and Legacy at Microsoft — Matthew Parkinson, Microsoft
arthuriantech
08.12.2019 15:09+1Сначала был Rust, который умел исключать ошибки при работе с памятью, но в это время группа сотрудников Microsoft обнаружила в Rust фатальный недостаток — его писали не они! Они немедленно исправили этот недочет, создав Verona, который как Rust, но другой.
Sychuan
08.12.2019 19:48+3Это не Микрософт создает новый язык, а Микрософт Ресерч, который много чего создает в том числе и языков. И это хорошо
arthuriantech
08.12.2019 20:52+1По иронии судьбы, мем про "фатальный недостаток" обязан своим рождением Майкрософту
История программных революций от Microsoft
PsyHaSTe
08.12.2019 16:27Как указывает ZDnet со ссылкой на Мэтта Миллера, специалиста Microsoft по безопасности, около 70% всех уязвимостей, которые были обнаружены в продуктах Microsoft в последние годы, были связаны с ошибками управления памятью.
Какой странный майрософт, все же знают что у настоящего программиста не бывает ошибок с памятью, особенно в программах написанных в последние годы. Вы покажите пару примеров кода, всем станет очевидно, что ни один программист в здравом уме такого не напишет.
?/sarcasm?PsyHaSTe
08.12.2019 16:33Кстати, очень любопытно окунуться в историю и посмотреть каким раст планировался в 2009-2010 годах (тыц). Видно, что это просто попытка избавиться от основных проблем С++, оставив всё остальное как есть.
faoriu
08.12.2019 19:58+2А потом кто-то добавил <> в Rust — и понеслась
impl<'a, 'b> PartialEq<Cow<'b, OsStr>> for &'a Path impl<T> Rc<[MaybeUninit<T>]>
и т. п.
PsyHaSTe
08.12.2019 20:07А в чем собственно проблема с
<>
? Пример абсолютно нормальный, поэтому непонятно, что хотели им показать.Hardcoin
08.12.2019 21:37+4Если этот пример нормальный для раста (а не специально сделанное извращение), то это явно довод против него (с раст знаком шапочно, перевести не смог)
PsyHaSTe
09.12.2019 11:17+1Ну вот так примерно будет выглядит в сишарпе:
class Reference<LifetimeA, Path> : PartialEq<Cow<LifetimeB, OsStr>> { ... }
Второй пример прямо не странслировать потому что в сишарпе нельзя условно наследовать интерфейсы только для части генерик аргументов. Примерно это может означать:
class Rc<MaybeUninit<T>[]> { ... }
Вся разница с шарповым кодом в том, что апострофы для лайфтаймов используются, да
&
вместоReference
. Вас так апострофы напугали?
a1ex322
08.12.2019 21:53+4Представленный синтаксис выглядит перегруженым и имхо менее дружелюбен к читателю чем синтаксис большинства популярных языков.
iskateli
08.12.2019 22:18Зато понятно что происходит, в Scala например, столько неявного происходит на строчку кода, что впору за голову хвататься.
Clasen01
09.12.2019 03:03нет, абсолютно непонятно) для меня, как для человека едва ли знакомым с Rust такой пример выглядит отталкивающе) имхо
red75prim
09.12.2019 12:04+3Я, как человек едва знакомый с албанским языком, ответственно заявляю, что понять там ничего невозможно.
Если не понимать, что такое лайфтаймы, трейты и т.п., то ничем не поможет и такая запись
declare lifetimes a, b implement trait PartialEquality<CloneOnWrite(b)<OsCompatibleStringSlice>> for reference(a)<Path>
Clasen01
09.12.2019 15:22я этот синтаксис хотя бы загуглить могу, могу поискать, что такое lifetimes, trait и т.д, если возникнет такая необходимость. Как гуглить конструкции вида
не очень понятно)impl<'a, 'b> PartialEq<Cow<'b, OsStr>> for &'a Path
PsyHaSTe
09.12.2019 15:43+1Это понятно если прочитать учебник по расту. На который емнип я потратил часов 6 чтобы прочитать от корки до корки.
Синтаксис учится один раз, а потом используется многократно. Поэтому вариант который взял раст на мой взгляд намного читаемее чем то что написано выше. Если в случае с
impl<'a, 'b> PartialEq<Cow<'b, OsStr>> for &'a Path
глаз сразу выцепляет "какие времена жизни, у кого, для кого", то в джава-стайл варианте выше глаз об стену текста разбивается
chupasaurus
09.12.2019 08:35Ох. Работал я в одном проекте с бэкендом на Scala, одним из главных локальных мемов был исходник одной из основных подсистем строк в 300. Первые 120 и последняя сотня просты и предельно понятны, но вот 80 строк собственно тела сервиса с первых трёх сворачивают мозг в межушный нервный узел, оставляя только 4 символа W, T,? и F в мыслях.Самое страшное — то, что этот код отлично справлялся с поставленными задачами с отличной производительностью, т.к. был в важной и нагруженной части проекта, но для внесения любых изменений команда «теряла» разработчика полностью на несколько часов.
Oplkill
09.12.2019 16:28а в чём проблема была зарефакторить этот участок кода?
chupasaurus
09.12.2019 19:01Пару раз при мне пытались, провисали по производительности или corner case-ам из боевого опыта.
Да, забыл отметить, текст был предельно читаемым (т.е. максимально далёк от программ ACM-щиков, не в обиду), но ему это не помогало.
Hab_Reader
09.12.2019 10:11+1Для меня это выглядит как Карго с новомодных шаблонов C++
= вместо того, чтобы от этого ужаса избавиться, в Rust — почему-то решили скарго-культить это извращение. :(
potan
09.12.2019 19:04А какая альтернатива шаблонам? Вынести типы как обычные параметры, как сделано в языках с зависимыми типами?
PsyHaSTe
09.12.2019 11:18Так предложите другой вариант. Просто я лично не вижу способа выразить это лучше, может я зашорен и не вижу очевидного варианта.
PsyHaSTe
09.12.2019 11:35Просто большинство популярных языков не предоставляет ту информацию, которую предоставляет раст. Например, там обычно нет связи между временем жизни аргументов и результатом функции. В расте можно написать функцию, которую вернёт лямбду, по времени жизни привязанную к времени жизни аргументов. То есть
fn f(x: &i32) -> impl Fn() -> i32 + '_ { move || *x } fn main() { let y; { let x = 5; y = f(&x); println!("{}", y()); } println!("{}", y()); }
С первым println всё хорошо, а вот со вторым — нет:
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
Поэтому сравнивать синтаксис с языками которые предоставляют меньше информации (например, в языке с ГЦ такое соответствие времен жизни указать нельзя, да и смысла там в этом мало) я считаю некорректно.
nikbond
09.12.2019 10:10А что, в других языках есть что-то более удобное для указания типовых параметров кроме <>? В вышеприведенной доке для этого другие скобочки [], но смысл-то от этого не меняется.
Ну да, конструкции типа
Arc<Mutex<Receiver<Option<Message<T>>>>>
Довольно многословны, но какие альтернативы? Разве что сделать какой-то разделитель одним символом, а не скобочками, типа
Arc!Mutex!Receiver!Option!Message!T
Но тогда как записывать, если типовых параметров больше одного? Какой синтаксис для лайфтаймов будет более удобен?ilammy
09.12.2019 11:03+2Довольно многословны, но какие альтернативы?
type Mailbox<T> = Arc<Mutex<Receiver<Option<Message<T>>>>>;
И теперь всего одна пара скобочек.
Antervis
09.12.2019 11:29можно вывести категорию «функции (шаблоны) с одним параметром-типом на входе и одним типом на выходе» как «модификаторы типа» и записывать вообще без спец символов — Arc Mutex Receiver Option Message T. Что-то вроде const в c++, но с адекватными правилами записи/чтения.
Amomum
09.12.2019 14:52У меня единственное возражение против угловых скобок — это не скобки! Поэтому редакторы очень часто не могут подсветить соответствующую закрывающую/открывающую угловую скобку.
У квадратных скобок такой проблемы нет. Ну и визуально — хотя это вкусовщина, конечно — квадратные скобки чуть меньше сливаются с текстом.
type Mailbox[T] = Arc[Mutex[Receiver[Option[Message[T]]]]];
type Mailbox<T> = Arc<Mutex<Receiver<Option<Message<T>>>>>;
firk
08.12.2019 20:05+2Какой странный майрософт, все же знают что у настоящего программиста не бывает ошибок с памятью, особенно в программах написанных в последние годы. Вы покажите пару примеров кода, всем станет очевидно, что ни один программист в здравом уме такого не напишет.
?/sarcasm?Это вобщем-то и без сарказма почти верно.
Просто "настоящие программисты" (в хорошем смысле) бизнесменам не нужны. Поэтому даже те, кто мог бы быть ими, обычно вынуждены играть роль плохих.potan
09.12.2019 19:08Даже настоящим программистам ни к чему делать лишнюю работу, которую можно переложить на компилятор. Или «настоящие программисты» кроме ассемблера ни чего не признают?
firk
10.12.2019 22:36Код на Си транслируется в ассемблер практически без оверхеда. Более того, современные компиляторы часто могут сделать такие оптимизации, которые вручную было бы делать крайне муторно. А если ещё эти оптимизации зависят от платформы то всё ещё лучше в пользу Си. Те же места, где компилятору не повезло (их мало но они встречаются) можно сделать ассемблерными вставками, если там критична скорость.
А вот с управлением памятью ситуация совершенно другая. Автоматическое управление памятью всегда создаёт оверхед, и работает хуже чем это может сделать программист вручную. И вряд ли ситуация сильно изменится если только этим не займётся AI. Ну, насчёт оверхеда есть одно почти исключение — c++ управление временем жизни объектов (не указателей) при должном уровне компиляторных оптимизаций и при качественной реализации конструкторов копирования/перемещения, операторов присваивания (всё это с полноценным учётом const/nonconst аргументов) и деструкторов этих самых объектов, на современных компиляторах может быть с довольно маленьким оверхедом. Однако обычно это даже не считают автоматическим управлением памятью.
potan
11.12.2019 17:17+1Rust позволяет управлять памятью практически так же точно, как и C/C++, только контролируя безопастность. Сам он удаляет объекты примерто так же, как C++ со смартпоинтерами, зачастую с меньшим оверхедом. Даже если хочется странного, типа иметь несколько указателей на объект и удалать его по любому из них, можно все это сделать через unsafe и сырые указатели.
firk
12.12.2019 01:54Вы то ли подменяете понятия то ли не понимаете сути. Я не знаю что и как в Rust, но ваши заявления касательно C/C++ странные.
Во-первых, "как C только контролируя безопасность" это и есть оверхед. В glibc например если поставить переменную окружения _MALLOC_CHECK=2 он тоже будет что-то контролировать, но это не продакшн функция а отладочная. Это если про само выделение/освобождение. Если же речь про невыход за границы выделенной памяти то это ещё больше оверхеда (при каждом обращении к массиву сверять индекс с чем-то в памяти, а уж как в таком режиме работать с type-casted указателями я вообще не знаю).
Во-вторых, когда я выше писал про c++ это было не про smart pointers а про RAII. Сам RAII добавляет немного (немного — повторюсь — на современных компиляторах и с качественной реализацией класса) оверхеда, а smart pointers с refcount — это абстракция над RAII которая добавляет ещё оверхеда. Если речь про без refcount то это тоже самое что статический объект. Случай с малым оверхедом это когда функционал smart pointer'а встроен в используемые классы, но не отдельной абстракцией а монолитно.
Иметь несколько указателей на объект это штатная фича указателей. А ещё бывают указатели на не-объект, например на позицию "+2 байта от начала переменной long long x;" (тип long long обычно 64-битный). То есть указатель это совсем-совсем не обязательно результат работы аллокатора для какого-то класса.
можно все это сделать через unsafe и сырые указатели.
То есть если хотим максимальной эффективности — возвращаемся в тому что было.
PsyHaSTe
12.12.2019 11:59Во-первых, "как C только контролируя безопасность" это и есть оверхед. В glibc например если поставить переменную окружения _MALLOC_CHECK=2 он тоже будет что-то контролировать, но это не продакшн функция а отладочная. Это если про само выделение/освобождение. Если же речь про невыход за границы выделенной памяти то это ещё больше оверхеда (при каждом обращении к массиву сверять индекс с чем-то в памяти, а уж как в таком режиме работать с type-casted указателями я вообще не знаю).
Почти все проверки раст делает во время компиляции, и рантайм проверки можно тоже выключить. Например, компилятор раста автоматически проверит, что у вас ссылки не алиасятся, и на все указатели/ссылки в прогармме повесит __restrict. Надо ли говорить, что это не замедляет, а ускоряет программу?
Во-вторых, когда я выше писал про c++ это было не про smart pointers а про RAII. Сам RAII добавляет немного (немного — повторюсь — на современных компиляторах и с качественной реализацией класса) оверхеда, а smart pointers с refcount — это абстракция над RAII которая добавляет ещё оверхеда. Если речь про без refcount то это тоже самое что статический объект. Случай с малым оверхедом это когда функционал smart pointer'а встроен в используемые классы, но не отдельной абстракцией а монолитно.
Когда у вас язык построен вокруг владения, вы можете весь RAII сделать статически, и не тратить время в рантайме на рефкаунтинг.
То есть если хотим максимальной эффективности — возвращаемся в тому что было.
С указателями эффективность может быть даже ниже, см. тот же пункт про алиасинг.
Antervis
12.12.2019 12:10концептуально в раст тот же плюсовый RAII, а безопасность обеспечивается в компайл-тайме. Реальный оверхед может быть на проверках там, где компилятор ожидаемо не может проследить гарантии, предоставленные вызывающим методом.
Иметь несколько указателей на объект это штатная фича указателей. А ещё бывают указатели на не-объект, например на позицию "+2 байта от начала переменной long long x;" (тип long long обычно 64-битный). То есть указатель это совсем-совсем не обязательно результат работы аллокатора для какого-то класса.
для таких случаев лучше иметь ссылку и смещение перенести поближе к использованию. А еще лучше вообще не складывать байты в целочисленные типы
Antervis
09.12.2019 11:41то, что уязвимости были обнаружены «в последние годы», не значит, что они не существовали с 80х.
proninyaroslav
08.12.2019 20:56И почему до сих пор ABI Rust нестабилен, как мне кажется это ключевая фишка, чтобы потеснить C++. Crates это конечно хорошо, только когда мы собираем монолитный бинарник. Каким образом Майкрософт будет осуществлять разработку системных компонентов? Она по большей части предполагает наличие динамических библиотек, а в Rust стабильность ABI можно гарантировать только на уровне определённой версии rustc. Они, конечно, могут ограничиться только написанием обособленных компонентов вроде драйверов, но это сильно занижает потенциал Rust.
nlinker
08.12.2019 23:27Совместимость с C поддеживается, а нативный растовый ABI не слишком нужен в условияк сборки через cargo.
Но пока слишком велик риск допустить архитектурную ошибку. Я надеюсь, разработчики запилят GATы, а сейчас активно пилятся const-generics и другие фичи, и заморозить ABI значит обратить всё в legacy. Я лучше буду мучиться с перекомпиляцией пока.
kuraga333
08.12.2019 23:47А может кто подробнее объяснить, почему это нет в Rust (и нет ли)?
Основным отличием Verona от Rust является применение модели владения на основе групп объектов, а не единичных объектов. Данные в Verona рассматриваются как структуры, представляющие собой коллекции объектов.
TargetSan
09.12.2019 13:35Для этого неплохо бы понять для начала, как выглядит эта модель владения "на основе групп объектов".
PsyHaSTe
09.12.2019 15:43Мне кажется, тут ноги растут отсюда: http://joeduffyblog.com/2015/11/03/blogging-about-midori/
potan
09.12.2019 16:39Вероятнее всего «фатальный недостаток».
Но по мне так конкуренция — хорошо. Может кто-нибудь наконец то HKT реализует.
iluxa1810
09.12.2019 08:40А чем .NET плох? Вроде, платформа стабильная, а так же есть ручное управление памятью.
Не понимаю смысла городить новые языки.FreeBa
09.12.2019 12:15У .net другая ниша. Тяжело на дотнете что-то системное пилить.
iluxa1810
09.12.2019 12:34Ну фиг его знает. А что мешает доработать .NET под это все дело?
Скажем, добавить новый синтаксис для взаимодействия с неуправляемым кодом и все такое.Fedorkov
09.12.2019 14:01Тогда получится C++/CLI, самый уродливый язык, когда-либо созданный для практических целей.
Либо ещё один Rust.iluxa1810
09.12.2019 14:15Ну… они могли бы поучиться над ошибками и сделать красивый синтаксис.
Fedorkov
09.12.2019 14:37Мне кажется, именно этим сабжевый отдел Microsoft и занимается.
Синтаксис C# действительно лаконичнее и читабельнее, но всё-таки zero-cost abstractions — это отдельная парадигма, под которую шарп изначально не затачивался, а если насильно натягивать язык на новую парадигму, мы получим ещё один C++ со всеми его проблемами.iluxa1810
09.12.2019 15:31+1Да, я согласен.
Однако, надеюсь, что дадут какой-нибудь способ взаимодействовать с ним из .NET.
pesh1983
09.12.2019 10:22Хм, либо Windows достигла критической точки, когда тех долг уже настолько большой, что развивать систему становится настолько сложно, что проще переписать ее часть. Либо в Microsoft качество специалистов упало
IvanNochnoy
09.12.2019 10:47+2Либо в Microsoft качество специалистов упало
Судя по моим последним наблюдениям, качество специалистов упало везде, зато увеличилось количество. В этой стуации попытка прейти на Rust выглядит стратегически перспективной.
ElvenSailor
09.12.2019 11:47-1ЕГО ПИСАЛИ НЕ ОНИ! (,)
опять "давай сделаем такой же *, только лучше, но другой".
Хотя цель благая вроде.
Им наконец надоело стрелять себе в ногу всякими там memset'aми.
Хм, либо Windows достигла критической точки, когда тех долг уже настолько большой, что развивать систему становится настолько сложно, что проще переписать ее часть. Либо ...
И ещё как.
YuriM1983
У Rust выявили «фатальный недостаток»?
faoriu
С другой стороны, если у Microsoft получится сделать из Rust что-то более user-friendly, наподобие C# — все только обрадуются. Ну и с поддержкой со стороны нормальных средств разработки, естественно.
nikbond
А чем Rust не user-friendly?
PsyHaSTe
Ну, если вы помните все перипетии и нюансы взаимодействия Pin/Unpin/!Unpin, когда что выводится, и когда надо потребовать анпин, а когда надо наоборот запретить анпин (двойное отрицание, привет!).
Ну и есть всякие другие фичи, но они скорее направленны на максимально эффективную компиляцию, вроде уникальных типов у разных лямбд. Это уже трейдофы и однозначным минусом это назвать нельзя. Но если это можно победить и код работающий я парой-тройкой замыканий перестанет выглядеть инопланетной дичью, то я только за.
nikbond
А как это относится к эффективной компиляции? Лямбды в Расте имеют разные типы по той же причине, что и в С++. Лямбда — это просто синтаксический сахар для анонимной структуры с соответствующим методом. Две лямбды — две разные структуры, соответственно тип у них разный.
Какую реализацию вы предлагаете как более удобную? С учетом того что язык компилируемый, нативный и с минимальным рантаймом.
PsyHaSTe
Ну можно было бы боксить по-дефолту и проводить эскейп анализ. Да, звучит сложно, но зато при необходимости связать пару функциональных параметров не пришлось бы городить монстров вроде такого: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=3c0bec29d4f38f8eedae7a42446f0480
Для сравнения. вот так этот же код выглядит на скале:
Whuthering
Синтаксис :)
PsyHaSTe
Предложите вариант лучше. Только, конечно, не потеряв в информативности.
Или это такой тонкий сарказм что я не распознал.
defuz
Искренне не понимаю людей, которых отталкивает чужеродность синтаксиса Rust. Его и так уже где только можно привели к C/C++, иногда даже в ущерб логике.
PsyHaSTe
Просто очередное изнасилование журналиста ученым (как всегда, ради громкого заголовка):
отсюда