LINUX.ORG.RU

Rust 1.13

 


4

10

Представлен релиз Rust 1.13 — системного языка программирования, нацеленного на безопасную работу с памятью, скорость и параллельное выполнение кода. В этот релиз вошли 1448 патчей.

Этот сезон оказался очень плодотворным для Rust. Проведены конференции RustConf, RustFest и Rust Belt Rust. Обсуждено будущее языка, разработан план на 2017 год и созданы новые инструменты.

Новое в 1.13

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

Cargo в этом релизе содержит важные обновления безопасности, связанные с зависимостями от curl и OpenSSL, для которых также недавно были опубликованы обновления безопасности. Подробную информацию можно найти в соответствующих источниках для curl 7.51.0 и OpenSSL 1.0.2j.

Оператор ?

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

fn read_username_from_file() -> Result<String, io::Error> {
    let f = File::open("username.txt");

    let mut f = match f {
        Ok(file) => file,
        Err(e) => return Err(e),
    };

    let mut s = String::new();

    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}

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

С оператором ?, вышестоящий код выглядит следующим образом:

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = File::open("username.txt")?;
    let mut s = String::new();

    f.read_to_string(&mut s)?;

    Ok(s)
}

Оператор ? заменяет весь код обработки ошибок, написанный при помощи оператора match ранее. Иными словами, ? применяется к значению Result, и если оно равно Ok, разворачивает его и отдаёт вложенное значение; если это Err, то происходит возврат из функции, в которой вы находитесь.

Более опытные пользователи могут заметить, что этот оператор делает то же самое, что и макрос try!, который доступен начиная с Rust 1.0. И будут правы, в самом деле, это то же самое. До 1.13 read_username_from_file можно было бы написать следующим образом:

fn read_username_from_file() -> Result<String, io::Error> {
    let mut f = try!(File::open("username.txt"));
    let mut s = String::new();

    try!(f.read_to_string(&mut s));

    Ok(s)
}

Так зачем надо было расширять язык, если до этого уже был такой макрос? Есть несколько причин. Во-первых, try! доказал своё огромное значение и часто используется в идеоматичном Rust. Он используется так часто, что было принято решение о создании собственного «подслащенного» синтаксиса для него. Такой вид эволюции — одно из преимуществ мощной системы макросов: расширения к синтаксису языка можно добавлять через прототипирование без внесения изменений в сам язык и особо полезные макросы могут указать на недостающие возможности языка. Эволюция try! в ? — яркий пример этого.

Другая причина — восприятие нескольких последовательных вызовов try!:

try!(try!(try!(foo()).bar()).baz())
против
foo()?.bar()?.baz()?

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

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

Более подробно об операторе ? можно прочитать в RFC 243.

Улучшение производительности

В последнее время очень много внимания заострено на производительности компилятора. Mark Simulacrum и Nick Cameron произвели улучшения http://perf.rust-lang.org/, инструмента для отслеживания производительности компилятора, на котором периодически запускается набор rustc-benchmarks на выделенном оборудовании. Инструмент записывает результаты каждого прохода компилятора и позволяет находить и отслеживать код, приведший к регрессии. Например, при помощи этого инструмента можно посмотреть график производительности за весь цикл разработки релиза 1.13, где можно увидеть заметное сокращение времени работы компилятора, отдельно представленное на соответствующей странице со статистикой.

Большое улучшение на графике от 1 сентября связано с оптимизацией от Niko по кешированию нормализованных проекций во время преобразования. То есть во время генерации промежуточного представления LLVM компилятор больше не пересчитывает каждый раз конкретные экземпляры связанных типов, когда они необходимы, а использует ранее вычисленные значения. Несмотря на то, что данная оптимизация не влияет на всю кодовую базу, для некоторого кода с определенным шаблоном, например, futures-rs, ускорение сборки в режиме отладки достигает 40%.

Другая оптимизация от Michael Woerister уменьшает время компиляции библиотек, экспортирующих множество встраиваемых функций. Когда функция помечена как «#[inline]», в дополнение к преобразованию этой функции в текущей библиотеке компилятор сохраняет её представление MIR и преобразует функцию в представление LLVM в каждой библиотеке, которая вызывает её. Оптимизация, сделанная Michael Woerister, позволяет компилятору избегать предварительных преобразований кода встраиваемых функций в библиотеках, в которых они определены, до их непосредственного прямого вызова. Таким образом, компилятор избавляется от необходимости выполнения лишних шагов по преобразованию функции в промежуточное представление LLVM, оптимизации LLVM и преобразования функции в машинный код.

В некоторых случаях это приводит к впечатляющим результатам. Например, время сборки библиотеки ndarray уменьшилось на 50%, а библиотека winapi 0.3 (ещё не опубликована) полностью избавилась от шага генерации машинного кода.

Но это ещё не всё: Nick Nethercote обратил своё внимание на производительность компилятора, сконцентрировавшись на профилировании и микрооптимизациях. Этот релиз включает в себя некоторые плоды его работ, ещё больше ожидается в 1.14.

Другие заметные изменения

Макросы теперь можно использовать на позиции типов (RFC 873), а атрибуты могут быть применены к операторам (RFC 16):

// Use a macro to name a type
macro_rules! Tuple {
    { $A:ty,$B:ty } => { ($A, $B) }
}

let x: Tuple!(i32, i32) = (1, 2);

// Apply a lint attribute to a single statement
#[allow(uppercase_variable)]
let BAD_STYLE = List::new();

Были удалены встраиваемые флаги сброса. Раньше при условном перемещении компилятор встраивал «флаг сброса» в структуру (увеличивая его размер), чтобы отслеживать, когда надо его сбросить. Из-за этого некоторые структуры занимали больше места, что мешало передаче типов с деструкторами поверх FFI. Благодаря тому, что в версии 1.12 добавлен MIR, появилась основа для многих улучшений, включая удаление встраиваемых флагов сброса. Теперь флаги сброса хранятся в дополнительном слоте в стеке тех функций, которым они нужны.

Релиз 1.13 содержит серьёзную ошибку в генерации кода для ARM с аппаратной реализацией чисел с плавающей точкой. Поскольку 1.13 содержит исправление безопасности, пользователям ARM рекомендуется использовать бета-версии 1.14, в которых скоро появится исправление для ARM.

Стабилизация языка

Стабилизация библиотек

Возможности Cargo

Более детальный список изменений доступен по ссылке: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-1130-2016-1...

>>> Подробности

★★★★★

Проверено: maxcom ()
Последнее исправление: cetjs2 (всего исправлений: 5)

Ответ на: комментарий от Legioner

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

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

интересно, когда в rust появится нечто подобное. и как бы мог выглядеть «сигнальный протокол ошибок» на Rust.

anonymous
()

А ведь раньше говорили, что perl - это единственный write only язык. Теперь вижу, что это далеко не так.

andreyu ★★★★★
()
Ответ на: комментарий от anonymous

Как вариант - посмотрите в сторону FreeBSD-шной sys/queue.h, для списков, которые дальше упоминали по треду, очень удобная, имхо, вещь.

anonymous
()
Ответ на: комментарий от RazrFalcon

Осталось понять, чем он отличается от ваших любимых крестов.

Действительно, это единственное, что осталось понять растолюбам.

andreyu ★★★★★
()
Ответ на: комментарий от anonymous

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

скажите

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

Esper
()

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

T a = function(arg0,arg1,arg2)?;
в С++ подобную штуку стоило бы ввести. на аппаратном уровне это делается например на х86 через флаг cf, например так:
push arg0
push arg1
push arg2
call foo;
jc error_in_eax_returned
add esp, <args_size>
а в самой функции через stc/clc можно выставлять признак ошибки.

i36_zubov
()

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

Для системы: Си, С++

Для Web: php,js

И вот оно счастие.

kartg
()
Ответ на: комментарий от RazrFalcon

То есть наезд был без пруфов?

Я лишь сказал, что читабельность вашего раста на уровне перла, который некоторые называют write only языком.

А вот вы зачем-то наехали на плюсы.

andreyu ★★★★★
()
Ответ на: комментарий от andreyu

Читабельность любого ЯП для неспециалиста стремится к нулю.
Субъективная оценка соверненно никакой смысловой нагрузки не несет.

Если нет конкретных объективных претензий — лесом, пожалуйста.

mersinvald ★★★★★
()
Ответ на: комментарий от mersinvald

Если нет конкретных объективных претензий — лесом, пожалуйста.

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

eao197 ★★★★★
()
Ответ на: комментарий от Legioner

Сравнивать надо с C, C++.

Раст-же не поддерживает столько платформ, сколько С/С++... Грустно сравнивать то, что работает на 1.5 платформах с тем что компилируется практически подо все, включая спектрум. ИМХО по этой самой причине говорить что раст - системный язык слегка рановато.

Q-Master
()
Ответ на: комментарий от RazrFalcon

Лехко:

fn firsts<'a, 'b>(x: &'a Vec<i32>, y: &'b Vec<i32>) -> (&'a i32, &'b i32)
Прям такой C++, С++...

У Rust-а вообще есть вменяемые приверженцы?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

И чем это отличается от C++? Порядок немного другой + доп. фишки типа лайфтаймов и всё. Сравните с упомянутым уже perl, или с python, haskell, lisp. На кого больше всего похож раст? Правильно - на C/C++.

RazrFalcon ★★★★★
()
Ответ на: комментарий от andreyu

Я лишь сказал, что читабельность вашего раста на уровне перла

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

anonymous
()
Ответ на: комментарий от Q-Master

Грустно сравнивать то, что работает на 1.5 платформах с тем что компилируется практически подо все, включая спектрум.

А давай конкретно - каких платформ тебе не хватает?

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

Сравните с упомянутым уже perl, или с python, haskell, lisp. На кого больше всего похож раст? Правильно - на C/C++.

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

Q-Master
()
Ответ на: комментарий от RazrFalcon

Начнём с того, что синтаксис раста совпадает с С++ чуть менее чем полностью.

Вот это поворот, лол. И кто-то после этого еще будет спорить, что раст не для крестофанов делали?

anonymous
()
Ответ на: комментарий от Q-Master

Мы точно про один и тот же rust говорим?

туча стрелочек

Точне не про раст. Тут стрелки только в описании функций. Ну и паттер матчинг, и то там уже другие стрелки.

прочих непонятных палочек и скобочек

template<typename... Args>
bool logicalAnd(Args... args) {
    // Binary folding.
    return (true && ... && args);
}
constexpr auto add = [] (int x, int y) {
  auto L = [=] { return x; };
  auto R = [=] { return y; };
  return [=] { return L() + R(); };
};

Еще вопросы?

RazrFalcon ★★★★★
()
Ответ на: комментарий от eao197

Кстати, как по мне, так на OCaml он похож сильнее

Это тылганер придумал или на редите кто-то ляпнул? Бред же.

anonymous
()
Ответ на: комментарий от RazrFalcon

1) В раст дженерики, а не шаблоны.
2) Мы про синтаксис.

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

anonymous
()
Ответ на: комментарий от RazrFalcon

Вы серьезно не понимаете, какой уровень совпадения синтаксиса подразумевают ваши же слова «синтаксис раста совпадает с С++ чуть менее чем полностью»?

eao197 ★★★★★
()
Ответ на: комментарий от RazrFalcon

А никто и не спорит.

Ну-ну, глава лоровской ячейки проповедников много лет убеждает, что раст - это си + окамл, а кресты мол не при делах. И ЦА у раста якобы сишники. Какие то у вас противоречия в секте.

anonymous
()
Ответ на: комментарий от Q-Master

А давай конкретно - каких платформ тебе не хватает?

Power*, к примеру.

Ясно. Вот список платформ, поддерживаемых Rust: https://forge.rust-lang.org/platform-support.html

Еще раз - чего тебе не хватает? Или не устраивает, что PowerPC - всего лишь Tier 2?

tailgunner ★★★★★
()
Ответ на: комментарий от RazrFalcon

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

anonymous
()
Ответ на: комментарий от RazrFalcon

Еще раз для тугих: мы тут о палочках и стрелочках, а не о том, что делает приведенный код.

И именно потому лалка шлангует, ведь данный макрос будет просто квинтэссенцией «палочек и стрелочек».

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.