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)

Я так понял, что try! останется, так что кому не нравится может все делать по-старому (а можно и вовсе match-ить вручную).

Молодцы ребята. Всех растазианцев (или как там правильно?) поздравляю!

php-coder ★★★★★
()
Ответ на: комментарий от reprimand

сказать нечего - проходи мимо.

Это был намек, что ты уже привык к си, поэтому тебе так кажется.

goingUp ★★★★★
()

Годно написанная новость, респект :)

goingUp ★★★★★
()

Эволюция try! в ?

Даже страшно представить дальнейшие ступени этой эволюции. А ведь беднягам ещё и тернарный оператор пото́м придётся добавлять.

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

А ведь беднягам ещё и тернарный оператор пото́м придётся добавлять.

Какой именно и почему «придется»?

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

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

Зачем тогда оператор ?, если «относились спокойно»?

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

они знают о монадах и не в восторге от них.

Не осилили просто.

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

Result и Option и так являются вполне полноценными монадами.

Монада это не только функтор, это ещё и соответствующие естественные преобразования.

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

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

Зачем тогда оператор ?, если «относились спокойно»?

О народе заботятся, но сами не фанатеют: https://www.reddit.com/r/rust/comments/5c9yky/announcing_rust_113/d9v6lup/

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

пото́м

в слове «потом» ударение не требуется. можно ставить в слове «по́том», но только в редких случаях, когда из контекста непонятно.

по теме: ну что ж, неплохо. пусть живёт.

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

И нет абстракции Monad, как в Хацкеле. Ты не сможешь написать код, который работает с абстрактной монадой, до тех пор, пока в Rust не впилят HKT, если я опять ничего не путаю.

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

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

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

если мне нужен чуть более сложный тип для обработки ошибок чем Result?

В таком случае в ветке Result::Err возвращаешь структуру, с помощью которой можно получить дополнительную информацию или даже незавершенный результат. Но если желаешь использовать оператор ? у произвольного типа - реализуй трейт Carrier.

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

std::ops.

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

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

quantum-troll ★★★★★
()
Ответ на: комментарий от asaw

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

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

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

? и вдруг аж выход из функции

О_О Я, прочитав текст новости, подумал что это для

var = condition ? penis : anus;

И удивился, что этого до сих пор там не было (не трогал Rust, да). А теперь оказывается, что это даже ещё бОльший ад =)

DELIRIUM ☆☆☆☆☆
()
Последнее исправление: DELIRIUM (всего исправлений: 1)
Ответ на: комментарий от shaiZaigh

Но если желаешь использовать оператор ? у произвольного типа - реализуй трейт Carrier.

Вот это интересно, спасибо.

std::ops

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

hateyoufeel ★★★★★
()
Ответ на: комментарий от quantum-troll

Что-то мне кажется, в таком виде это не взлетит.

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

Да по сути так и есть (особенно checked exceptions). Та же фигня и с null'ом.
А в Расте ни того, ни другого. И лично мне это нравится.

kovrik ★★★★★
()

Руст - говнуст. Чем это поделие лучше классических Цэ и Цэпипи? По виду какая-то лютая смесь цацкеля с перлом. И такая же нечитабельная.

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

Руст - говнуст.

http://www.linux.org.ru/people/Hertz/profile

Город: Говновосибирск

Кому-то не мешало бы к психоаналитику.

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

Зачем им тернарный оператор, если в Rust if — выражение?

Зачем им оператор ?, если тоже самое делается с помощью стандартного макроса?

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

Но если желаешь использовать оператор ? у произвольного типа - реализуй трейт Carrier.

«Users of ? should not rely on any implementations of Carrier other than Result, i.e., you should not expect ? to continue to work with Option, etc.».

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

Потому, что rust не поддерживает выражения вне {}.

if flag 
    some();

В расте писать нельзя, хотя в C/C++ это нормальный код.

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

Чем тред про HKT на реддит закончился, раст когда-нибудь станет юзабельным или решили что слишком сложно?

qnikst ★★★★★
()

Как шикарно оформлена новость. Спасибо за старания. Язык развивается, это радует.

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

Упс, перепутал с чем-то другим, простите.

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

Он про то, что например у тебя тип

enum IResult<a,b>=More(Fun<a,IResult<a,b>)|Done(b)|Failure(str)

И по ? Хотелось бы пробрасывать наверх Failure и More.

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

В том-то и дело, что C++/Java-style exceptions — зло (по их мнению). В Rust, Go и Swift от них отказались.

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

Legioner ★★★★★
()

Объясните толком, зачем оно нужно? Вот изучаю Питхон, может что-то не то делаю? Чем оно лучше?

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

Монада это не только функтор, это ещё и соответствующие естественные преобразования.

Которые реализованы в Rust.

Zenom ★★★
()

Если в свое время 10 раз неосилил C, а осилил тока Питон, то за Rust даже браться не стоит? :)

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

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

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