LINUX.ORG.RU

Rust 1.9

 


0

3

Анонсирована очередная версия языка программирования Rust 1.9, разрабатываемого Mozilla совместно с сообществом. Примечательно то, что с момента релиза первого стабильного выпуска прошел 1 год.

Основные изменения:

  • Стабилизирован модуль std::panic, позволяющий перехватывать раскрутку стека. Соответствующие функции рекомендуется применять только в исключительных ситуациях, но никак не для эмуляции механизма try-catch.
  • Стабилизированы методы настройки TCP и UDP соединений; расширены возможности OsString, BTreeSet и HashSet; char может быть получен из UTF-16 последовательности; стабилизирована функция copy_from_slice(); появилась возможность работы с волатильными переменными с помощью read_volatile и write_volatile; сырые указатели обрели .as_ref() и .as_mut(), которые возвращают Option<&T>, где null будет представлен как None; в libcore для всех типов реализован Debug.
  • Разработчикам библиотек доступен атрибут #[deprecated], разрешающий компилятору слать предупреждения при использовании устаревшего API.
  • Специализация уже используется в ночном релизе и будет доступна в стабильном 1.11 через 3 месяца, но оптимизация .to_owned() и .to_string() таки попала в текущий стабильный выпуск.
  • Расширен список поддерживаемых платформ: mips-unknown-linux-musl, mipsel-unknown-linux-musl, i586-pc-windows-msvc.
  • Ускорено время компиляции монады с одинаковыми функциями.

Изменения в менеджере зависимостей Cargo:

  • В системе могут работать несколько cargo одновременно, блокировки теперь применяются на файлы.
  • Переменную окружения RUSTFLAGS можно использовать для передачи произвольных флагов компилятору.

Для кросс-компиляции подготовлен инструмент rustup, обеспечивающий тривиальное взаимодействие с каналами сборок компилятора (stable, beta, nightly), стандартными библиотеками и их документацией к различным операционным системам, а также обновление всего этого зоопарка одной командой.

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



Проверено: Falcon-peregrinus ()
Последнее исправление: shaiZaigh (всего исправлений: 2)
Ответ на: комментарий от bbk123

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

А что, вместо этого, предлагают Rust, Go и прочии Swift-ы?

Явную обработку ошибок? Я думаю не зря все новые языки идут без исключений, ибо это лишнее усложнение.

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

Это позволяет унифицировать обработку исключений

Обработка исключений позволяет унифицировать обработку исключений. Прекрасно. А обработку ошибок унифицировать позволяет? Коды возврата запрещены?

tailgunner ★★★★★
()

Исключения имеют смысл в языках с навороченным ООП, типа C++. Rust же прямой как палка, исключения в нем были бы как собаке пятая нога.

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

Исключения гораздо более удобный механизм для обработки ошибок

В теории - да. На практике всё оказывается сложнее. Проблемы в реализации исключений. Их три больших группы (в С++).

1. Исключения медленные. Очень. Они почти не влияют на скорость программы, если исключение не бросается (разве что делают невозможными некоторые оптимизации). Но если исключение бросается, то оно дорогое. И чем длиннее стек, тем дороже. Короче, они не могут бросаться часто.

2. Они плохо согласуются с другими конструкциями языка С++, иногда это приводит к неопределенному поведению и утечкам ресурсов. Чем больше проект, тем больше вероятность нарваться на такие неприятные сюрпризы.

3. До последнего времени они более-менее хорошо были реализованы только для x86/x86_64. Для других платформ — тормоза и глюки, если вообще работало.

Короче, исключения в крупных проектах создают больше проблем, чем решают. Они несколько упрощают код, но появляется риск нарваться на UB. Отслеживать согласованность исключений с другими конструкциями языка приходится, в основном, вручную (плюс санитайзеры). Так что в итоге код с исключениями в С++ получается сложнее, а не проще. Доказательство корректности работы программы в условиях исключение — та еще проблемка.

Из-за тормозов исключений, код, критичный к производительности, всё равно приходится делать с явным возвратом и обработкой кода ошибки.

Поэтому некоторые решают вопрос кардинально, как в Rust. Или в Гуле. Запретить исключения, и точка. Я, лично, с этим не согласен (я, наверное, еще не нарывался на этот страшный UB), но эти мотивы понимаю.

//Психиатр

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

не готов для десктопа, плазма падает

Дальше не читал.
RazrFalcon

Потому как снова плазма упала? :-)

anonymous
()

Уважаемые растаманы.

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

Это действительно так или грязные инсинуации?

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

Наследования нет, полиморфизм — есть (как и в любом другом живом языке, который не С). Серво слишком tl;dr чтобы его читать, так что про костыльность не скажу.

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

Не знаю за другие языки, но в плюсах (xml)dom с полиморфизмом - это ад. Как с точки зрения кода, так и с точки зрения безопасной работы с памятью. Знаем, плавали.

В раст пока с деревьями и графами туго, делают через вектора + enum. Зато безопасно и быстро. Реализация не намного сложнее того же C++.

https://github.com/SimonSapin/rust-forest

наследование и полиморфизм

Оно пока и не нужно. Ибо есть aggregation и traits.

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

Явную обработку ошибок? Я думаю не зря все новые языки идут без исключений, ибо это лишнее усложнение.

Разве, для примера, в Java она неявная? Но исключения позволяют сосредоточить эту обработку в минимуме мест. Пока что исключения выглядят более привлекательными. Попробуй объясниться ещё раз.

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

Ошибка так же является исключительной ситуацией. Поэтому какие проблемы? Получил HTTP 500, брось исключение и слови его в том месте, где можешь обработать соответственно своей бизнес логики.

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

Еще раз: вынос обработки исключений из основного тела программы и есть усложнение.

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

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

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

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

Попробуй объясниться ещё раз.

Я не ваш подчиненный.

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

Ошибка так же является исключительной ситуацией.

В любой непонятной ситуации - кидай исключение. (с) Java

Нет. Исключения предназначены, что следует из названия, для исключительных ситуаций. Произошло то, чего произойти не должно.

Не смогли прочесть файл - это не исключение, я вероятность. Мы можем ее спокойно обработать.

Выход индексации за пределы вектора - исключение. Такого быть не должно.

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

Как раз таки Result|Option - это сплошной гемор. Поэтому в растике надо на каждый чих писать мурос типа try! и unwrap.

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

Поэтому в растике надо на каждый чих писать мурос типа try! и unwrap.

Фу таким быть. В расте нужно обрабатывать каждый чих. Не try! и unwrap, а match и if let.

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

Сначала бы хоть поддержку arm-unknown-linux-gnueabihf в Tier 1 перенесли. Может тогда в archlinuxarm появится. А пока оно какое-то x86-only поделие

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

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

А покажите пример? Из своей практики. Вот, мол, этот код с кодами ошибок лучше, чем вот такой код с исключениями.

Еще было бы интересно посмотреть, как на кодах ошибок будут выглядеть аналоги C++ного accumulate:

template<class InputIt, class T, class BinaryOperation>
T accumulate(InputIt first, InputIt last, T init, 
             BinaryOperation op)
{
    for (; first != last; ++first) {
        init = op(init, *first);
    }
    return init;
}

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

Без понятия. Я не перевариваю std::algorithms. Да и что здесь может выкинуть исключение?

В раст все просто:

let sum = (1..11).fold(0, |sum, x| sum + x);
vs
std::vector<int> v{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = std::accumulate(v.begin(), v.end(), 0);
Возможно есть вариант и попроще.

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

Давайте по пунктам.

Во-первых, вы сказали, что в вашей практике исключения приводят к худшему коду, нежели коды возврата. Покажите, пожалуйста, хотя бы один пример.

Во-вторых, был приведен код обобщенной реализации accumulate (в других языках это же может называться foldr, inject или reduce). Этот код может применяться к разным типам данных. Например, в качестве T может быть не только int, но и string или vector<string>. Причем, за счет использования исключений, эта реализация accumulate будет нормально работать, например, вот в таких случаях:

- исключение бросает операция сравнения first и last (могут быть хитрые реализации итераторов, которые делают проверку на принадлежность к одной и той же последовательности);

- исключение бросает операция ++first (например, итератор может контролировать выход за пределы разрешенного диапазона);

- исключение бросает операция op(init, *first);

- исключение бросает оператор присваивания нового значения init.

И это только то, что лежит на поверхности.

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

Вы же мне показали как в Rust-е дернуть готовую fold. Но это не то, что нужно было.

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

Как раз таки Result|Option - это сплошной гемор. Поэтому в растике надо на каждый чих писать мурос типа try! и unwrap.

В синтаксическом плане станет сильно приятней, если вот это попадет в stable.

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

Надо больше закурючек. Предложить чтоли им <file> для чтения из файла )

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

Или в Гуле. Запретить исключения, и точка.

Things would probably be different if we had to do it all over again from scratch.

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

Все намного проще. Я принципиально избегаю кода, который вы описали. Поэтому и примеров привести не могу.

Как только начинается логика вида: там, где-то, кто-то, может быть, а может и не кидает исключение - такой код на помойку.

Есть метод - он возвращает: ничего, значение, ошибку, значение+ошибку. Всё неявное поведение искореняется.

Например, в качестве T может быть не только int, но и string или vector<string>

Да, rust версия не настолько обобщенная:

let v = vec!["Hello", "world"].iter().fold(String::new(), |sum, x| sum + x );

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

Как только начинается логика вида: там, где-то, кто-то, может быть, а может и не кидает исключение - такой код на помойку.

Ну так покажите пример кода, который вы предпочитаете писать.

Да, rust версия не настолько обобщенная:

Вы опять показали, как вызвать готовый fold. Покажите, пожалуйста, как бы вы реализовали fold. На кодах ошибок.

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

Ну так покажите пример кода, который вы предпочитаете писать.

Я показал.

Покажите, пожалуйста, как бы вы реализовали fold. На кодах ошибок.

Реализация fold есть в сорцах rust - так и реализовал бы. Коды ошибок тут не нужны. Здесь нечему падать. А если и было бы чему - я бы написал развернутую версию на циклах.

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

Покажите, пожалуйста, как бы вы реализовали fold. На кодах ошибок.

Если я тебя правильно понял:

use std::iter::Iterator;

fn fold_result<T, I, R, E, F>(iter: I, init: R, mut f: F) -> Result<R, E> where
    I: Iterator<Item=T>,
    F: FnMut(R, T) -> Result<R, E> {
    let mut accum = init;

    for item in iter {
        accum = try!(f(accum, item));
    }

    Ok(accum)
}

fn main() {
    let numbers = [1, 2, 3, 5, 6, 7];

    let sum_success =
        fold_result(numbers.iter(), 0, |x, y| if y % 4 == 0 { Err("divisible by four") } else { Ok(x + y) });

    assert_eq!(sum_success, Ok(24));

    let sum_failure =
        fold_result(numbers.iter(), 0, |x, y| if y % 3 == 0 { Err("divisible by three") } else { Ok(x + y) });

    assert_eq!(sum_failure, Err("divisible by three"));
}

Можешь сравнить с оригинальным fold:

    fn fold<B, F>(self, init: B, mut f: F) -> B where
        Self: Sized, F: FnMut(B, Self::Item) -> B,
    {
        let mut accum = init;
        for x in self {
            accum = f(accum, x);
        }
        accum
    }
theNamelessOne ★★★★★
()
Ответ на: комментарий от RazrFalcon

У меня есть ощущение, что разговаривать приходится с «малолетним дебилом» (с).

Вы говорите, что:

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

Прошу показать пример подобного кода — вы этого не можете сделать.

Прошу вас показать, как бы вы реализовали accumulate/inject/reduce/fold с кодами ошибок: вы не можете этого сделать и показываете использование уже готового fold.

До этого вы мне приписали тезис о том, что в Dropbox-е весь код на Go. А в доказательство этого привели мою же фразу, где сказано, что часть кода была переписана с Python-а на Go.

По поводу out-of-memory вы высказываетесь в типичном для «малолетних дебилов» духе: пусть падает.

Ну и как после этого прикажете воспринимать ваше мнение о программировании вообще и о предпочтениях кодов возврата исключениям в частности?

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

Да, спасибо. Это то, что хотелось увидеть.

Правильно я понимаю, что предполагается, что:

for item in iter { // (1)
   accum = // (2)
     try!(f(accum, item));
}
В точках 1 и 2 никаких ошибок возникнуть не может в принципе?

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

В точках 1 и 2 никаких ошибок возникнуть не может в принципе?

В точке (1) может быть только паника. Цикл for работает, вызывая метод .next() итератора, который может вернуть либо Some(value), если есть следующее значение, либо None.

В точке (2) как раз происходит “обработка кодов ошибок”. try! — это макрос, а конструкция accum = try!(f(accum, item)); разворачивается примерно таким образом (упрощенно):

accum = match f(accum, iterm) {
  Ok(value) => value,
  Err(err) => return Err(err) // возврат "кода ошибки"
};
theNamelessOne ★★★★★
()
Ответ на: комментарий от eao197

Прошу показать пример подобного кода — вы этого не можете сделать.

Как я могу показать абстракцию? Предлагаете наваять 100500 строк кода, в одной части которого я кидаю исключения, а где-то в main их ловлю? Вот это и есть размазывание.

Прошу вас показать, как бы вы реализовали accumulate/inject/reduce/fold

Еще раз. Я не использую данные подходы вкупе с исключениями. Мне достаточно того, что я не пихаю в них код, который может отработать неверно. Да, мне плевать на OOM. Мне плевать, что в какой-то вселенной оператор сравнения может выкинуть исключение.

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

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

В 10-й раз: https://news.ycombinator.com/item?id=11283758

Dropbox rewrote Magic Pocket in Golang, and then rewrote it again in Rust,

По поводу out-of-memory вы высказываетесь в типичном для «малолетних дебилов» духе: пусть падает.

Вы даже представить себе не можете, как мало областей, где есть необходимость отлавливать OOM. 99% прикладного софта не отлавливает OOM от слова вообще.

Ну и как после этого прикажете воспринимать ваше мнение о программировании вообще и о предпочтениях кодов возврата исключениям в частности?

Мне плевать, как вы оцениваете мое мнение. Несогласны - игнорируйте.

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

В точке (1) может быть только паника.

Т.е. без исключений (пусть даже в виде паники) все-равно не обходится.

В точке (2) как раз происходит “обработка кодов ошибок”.

Может я чего-то не понимаю, но try! контролирует успешность работы f(). Далее, если f возвращает Ok(value), то этот Ok(value) должен быть сохранен в accum. Вот это сохранение всегда происходит без возникновения ошибок? Даже если value — это большой и хитрый value-type с собственной реализацией оператора копирования?

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

Далее, если f возвращает Ok(value), то этот Ok(value) должен быть сохранен в accum.

Конструкция match возвращает результат последнего выполненного выражения (в данном случае value), этот результат и присваивается accum.

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

Как я могу показать абстракцию?

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

Может там очередной фейспалм.jpg окажется.

Мне же достаточно что бы прога упала и все.

Замечательно.

В 10-й раз:

Не нужно в 10-й. Достаточно всего лишь второй раз макнуть вас вот в это:

Я оспаривал ваш тезис о том, что там всё на Go.

Вы так и не показали, где я озвучил этот тезис.

Мне плевать, как вы оцениваете мое мнение.

Уже понятно, что вам плевать и на качество кода тоже.

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

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

Конструкция match возвращает результат последнего выполненного выражения (в данном случае value), этот результат и присваивается accum.

Про это и речь. Там идет присваивание указателей? Побитовое копирование значения value или что-то другое?

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

Т.е. без исключений (пусть даже в виде паники) все-равно не обходится.

Это не С++. Если там вызывается код, который не генерирует панику, то паники не будет, в отличии от, где из-за buffer-overrun'а там может вызываться код инжектированного эксплойта.

Вот это сохранение всегда происходит без возникновения ошибок? Даже если value — это большой и хитрый value-type с собственной реализацией оператора копирования?

Если бы была собственная реализация оператора клонирования, то было бы try!(f(accum, item)).clone() , а копирование - это всегда побитовое копирование.

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

Там идет присваивание указателей? Побитовое копирование значения value или что-то другое?

Зависит от типа. Емнип, если число, то копирование, иначе присваивание указателей.

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

Если там вызывается код, который не генерирует панику, то паники не будет

Феерично. Т.е. если мы используем концепцию итерации по содержимому массива, то все зашибись. Если же мы пытаемся применить ту же концепцию итерирования по произвольной последовательности, то что тогда? Что, если последовательность у нас — это последовательность входящих сообщений из MQ-шного топика? Или последовательность строк из SQL-ного запроса? Или последовательность случайных чисел, читаемая из аппаратного HSM?

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

Емнип, если число, то копирование, иначе присваивание указателей.

Понятно. Спасибо.

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

Семантика копирования для Copy-типов - всегда побитовое копирование.

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

Что, если последовательность у нас — это последовательность входящих сообщений из MQ-шного топика?

В таком случае нужно будет предусмотреть это в сигнатуре итератора. Итератор будет возвращать не MQTopic, а Result<MQTopic, Error>.

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

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

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

Вы же пишете какой-то код, в котором обходитесь без исключений?

99% прог на Qt без исключений. Изучайте.

попадаете ли вы в их число. Очевидно, что попадаете.

Да. Я попадаю в число тех же разработчиков, что пишут firefox, chromium/webkit, qt, llvm, opencv ну и почти весь крупный софт.

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

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

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

99% прог на Qt без исключений.

Ага, миллионы мух же не могут ошибаться.

Я попадаю в число тех же разработчиков

И много вашего кода в firefox, qt или llvm?

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

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

Вот, например, неужели вы постоянно пишете new(nothrow)? Или вы никогда не делаете some_vector_with_strings.push_back(«another_value»)?

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