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)
Ответ на: комментарий от RazrFalcon

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

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

Человек

Не нужны такие человеки, они всё равно логических ошибок наделают, сабж не поможет.

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

В большом да - про memory safety. Вместе с cpp core guidelines имеем почти лайфтаймы, только (пока) непроверяемые.

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

только (пока) непроверяемые.

Ну так о чём тогда разговор?

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

Я вот изучаю с++. И rust. Немного уже классы прошел. Но на ваш код посмотрел и не смог понять ничего. Неужели в основном пишут такой код, как вы привели? Как дальше жить? Какой яп мне изучать?

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

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

Пишут на C++ ну очень сильно по разному.

Какой яп мне изучать?

Смотря зачем :)

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

Qt что ли? Тогда без вариантов. Можно конечно костылять на PyQt, но тут на любителя.

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

Для себя (для души) или за зарплату?

Если за зарплату, то изучайте тот язык, с которым вам будет проще работу найти (не знаю, что происходит в вашем регионе - это может быть и C++, и Java, и C# и еще что-то, включая JavaScript).

Если для себя и выбор стоит между C++ и Rust, то пока имеет смысл сосредоточится на C++. Rust разработками уровня Qt, wxWidgets, FLTK, FOX и пр. еще не оброс. Тем более, что в случае чего с C++ на Rust вы перейдете. После C++ на любой императивный язык несложно перейти.

eao197 ★★★★★
()
Последнее исправление: eao197 (всего исправлений: 1)
Ответ на: комментарий от RazrFalcon

Я не понял о чём говорит автор.

struct S1 {}

trait T1 {
    // куча методов
}

impl T1 for S1 {
    ...
}

struct S2 {}

trait T2 {
    // куча методов
}

impl T2 for S2 {
    ...
}

struct S3 {
    s1: S1,
    s2: S2,
}

impl T1 for S3 {
    // много механического бессмысленного кода
}

impl T2 for S3 {
    // много механического бессмысленного кода
}
DarkEld3r ★★★★★
()
Ответ на: комментарий от kartg

Си, С++
php,js

Зачем аж из двух вариантов выбирать? Надо до одного сократить!

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

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

Я пишу на плюсах и скажу тебе, что для кучи народу С++ тоже нечитаемый язык. Раст в некоторых места лучше, в некоторых хуже из-за введения новых концепций типа лайфтаймов.

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

Не понял пример. Зачем делать поля приватными? Достаточно обращаться к ним напрямую, тогда последние два impl ненужны.

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

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

Пишут на C++ ну очень сильно по разному.

У меня есть один из критериев оценки языков программирования, когда я оцениваю понятность, а также стиль того, как написаны основные библиотеки. Исходники STL и Asio обычно вспоминаю как страшный сон. В STL заглядывал постоянно, а в Asio - эпизодически. Чур - меня чур. А вот стандартная библиотека Java - очень даже ничего, неплохо написана! ;)

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

Зачем делать поля приватными?

Затем, что это может быть нужно. Давай тогда вообще «приватность» уберём - не надо будет геттеры/сеттеры писать вообще, удобно-то как.

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

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

В идеале хотелось бы более мощного сахара, как-то так:

impl T1 for S3 {
    // переопределяем некоторые методы
    fn foo() { ... }
    fn bar() { ... }

    // остальные делегируются s1
}
Как именно делегирование будет выглядеть - не принципиально. Главное, что это позволит меньше мусора писать. Так любимая некоторыми «очевидность» не пострадает, а даже наоборот - сейчас придётся руками писать все методы T1 делегируя реализацию вручную, в итоге глаз просто не зацепится за то, что отдельные методы могут быть реализованы иначе.

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

Затем, что это может быть нужно.

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

Давай тогда вообще «приватность» уберём - не надо будет геттеры/сеттеры писать вообще, удобно-то как.

Так вот они как раз нормально реализуются. Даже без трейтов. То что вы хотите - это ООП наследование.

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

Мне не хочется. Не понимаю зачем это нужно.

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

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

Я считаю, что если бы у Rust-а был синтаксис, который бы позволил с минимальными усилиями преобразовать, скажем, вот такой C++ный код... то Rust-у было бы гораздо проще занять свое место под Солнцем, чем при его нынешнем синтаксисе.

Не похоже, что D это сильно помогло.

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

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

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

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

Мне не хочется.

Не надо быть таким твердолобым: многим не нужны макросы, по крайней мере, те, которые плагины. И без ? успешно обходились и без кучи разных удобств. Да чего, там - многим сам раст не нужен. К счастью, это, как и твоё «не нужно» ничего не значат.

Кстати, про «сооружение ООП» - некоторые вполне успешно Deref для этого эксплуатируют и ничего.

DarkEld3r ★★★★★
()
Последнее исправление: DarkEld3r (всего исправлений: 2)
Ответ на: комментарий от anonymous

Прописал необходимые инструкции в требованиях к стилю кода и всё: весь персонал пишет на «С с классами».

Это плохо работает, если не сопровождается автоматизированными проверками.

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

сам раст не нужен

Самая здравая мысль в треде.

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

Не похоже, что D это сильно помогло.

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

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

Иди побираться в другое место.

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

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

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

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

Хотя к D есть много других вопросов.

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

В STL заглядывал постоянно

В STL от кого? Их несколько разных.

А вот стандартная библиотека Java - очень даже ничего, неплохо написана!

Ага, и не тормозит. Сравнивать реализации библиотек в языках с GC и без оного — это мощно, да.

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

В STL от кого? Их несколько разных.

Linux, g++

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

Причем здесь это вообще?!

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

Не похоже, что D это сильно помогло.

Смотря про какой D идет речь. Во времена D1 код из C with Classes в D1 конвертировался без особых проблем. Но потом появился D2 и это уже началась совсем другая история.

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

Linux, g++

По-моему, самая читабельная реализация STL была в STLPort. Самая нечитабельная — в STL в MSVC++.

Причем здесь это вообще?!

Вообще-то при всем.

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

Внезапно: всякие :: . -> & * | >> => есть и в Rust-е. Только там они еще приправлены магическими сочетаниями &'х, mut &'y. При том, что я не большой фанат синтаксиса C++, но разработчики Rust-а умудрились таки пробить дно.

Если это единственная проблема, то тут можете не расстраиваться. Стрелочки почти те же, что и в C++, исчезли "--", «++», «~» и "?:", появились «=>» и «'a» и "!(". Ну если строго считать, то в плюсах ещё больше символьной белиберды, всякое «[]», «[=]», «[&]», «&&» (в значении r-value ссылка) и ~className против прямых скобок для растовых лямбд. Короче, до «дна» C++, авторы раста не дотянули.

А вообще ваша идея замены стрелочек словами как раз ущербна.

Да, объявления раста могут быть шумнее, но только потому, что это объявление тупо содержит больше информации. Аналогичное объявление в C++ со всеми core guidelines лайфтаймами не менее шумно, а если вспомнить <class/typename T> в шаблонах, так хоть стой, хоть падай. Но «стрелочки» - это как раз способ уменьшить шум. Подсветка синтаксиса в IDE появилась не просто так, программисту необходимо быстро отличать конструкции языка от свободно названных сущностей, вот и приходится цветом выделять. Символьные же последовательности заметно выделяются из текста, даже без раскрашивания в разные цвета, если их немного, то проблем нет. В Расте немного, меньше чем в C++, я уж не говорю о какой-нибудь скале.

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

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

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

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

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

Делегирование остального - плохая идея, то, что как раз стандартные языки с наследованием портит. Делегирование должно быть явным. Вроде обещают процедурные макросы, так что, возможно, через какое-то время можно будет писать не только #[derive(Debug)], но и что-нибудь типа #[delegate(member, method, Trait1, Trait2)]

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

Чтобы максимально запутать библиотеку коллекций? Ну, хорошо

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

Вы в языках с GC много подобных оптимизаций видели в библиотеках?

eao197 ★★★★★
()

Товарищи спецы по rust: когда следует ожидать кроссплатформенную(linux/windows) удобную библиотеку для gui? Желательно под крылом mozilla. Не привязки и обертки ко всяким gtk|qt и прочему, а собственное что-то. Нет каких-нибудь «инсайдерских» сведений?

Очень интересует. Хочу писать гуи софт для десктопа на расте. Чтоб просто и надежно.

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

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

когда следует ожидать кроссплатформенную(linux/windows) удобную библиотеку для gui? Желательно под крылом mozilla. Не привязки и обертки ко всяким gtk|qt и прочему, а собственное что-то. Нет каких-нибудь «инсайдерских» сведений?

Я не думаю, что здесь есть инсайдеры разработки Rust :) Так-то проекты существуют, да - Conrod и вроде еще что-то.

По моему личному мнению, наиболее близкий кандидат на роль «родного GUI для Rust при участии Мозиллы» - это WebRender.

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

Гуя для раста как мне кажется ждать точно не стоит — в языке даже банального ООП нет, на него задачи вроде гуя будут ложится очень и очень криво.

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

А интерфейс фаерфокса останется на чём написан — у них явно есть задачи поважнее.

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

Хочу писать <...> софт <...> на расте
Чтоб просто и надежно.

Ахаха.

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

Perl в разы понятней крестов. Я бы даже сказал на порядки понятней и выразительней.

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

Гуя для раста как мне кажется ждать точно не стоит — в языке даже банального ООП нет, на него задачи вроде гуя будут ложится очень и очень криво.

Ой, да ладно, WinApi, например, успешно реализует «ООП» на чистом C не имея вообще никакой поддержки ООП на уровне языка. Наследование реализаций типа чекбокс и радиобаттон являются наследниками тОгллбаттон, который наряду с пУшбаттоном является наследниками бАттона всегда было сомнительным, особенно в кроссплатформенном фреймвёрке, использующем нативные компоненты. Всё равно почти вся реализация оказывалась в листьях дерева типов. Проблема раста в гуифреймвёрке скорее в отсутствии рефлексии, современные фреймвёрки сплошь завязаны на динамический датабиндинг, а на расте только кодогенерация, так что ничего принципиально лучше чем qt не получится. Поэтому для начала написали биндинги на gtk, а дальше, видимо, ждут процедурных макросов.

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

Очень не скоро. Как и у всех остальных современных и не очень языков.

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

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

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

Qt тоже не подарок. Но написание такого монстра с нуля займёт годы на любом языке.

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

А где у файрфокса в гуйне хоть что-то «нативное»?
Интерфейсы браузеров уже давным давно пишут на html+js+css и рисуют на движке.

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