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

Что-то вроде (в предположении, что original_mq_iterator подгружает элемент внутри operator*):

class my_mq_iterator_wrapper {
  original_mq_iterator it_;
  bool failed_{ false };
public :
  my_mq_iterator_wrapper(original_mq_iterator it) : it_(move(it)) {
    load_current();
  }

  T& operator*() {
    if( failed_ ) throw runtime_error("...");
    return *current_;
  }

  bool operator!=(const my_mq_iterator_wrapper & end) const {
    if( failed_ ) return false;
    else return it_ != end.it_;
  }

  my_mq_iterator_wrapper & operator++() {
    if( !failed_ ) { ++it_; load_currenr(); }
    return *this;
  }
private :
  void load_current() {
    try { *it_; }
    catch(...) { failed_ = true; }
  }
};

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

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

Особенно, если в проект не подтянута библиотека, которая бросает int или std::string вместо std::exception.

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

Согласен, семантика таки разная. Спор шел о другом, сразу не заметил.

red75prim ★★★
()

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

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

Концепция итераторов. Вопрос стоял о исключениях в монадах и как это будет работать с аналогом плюсового accumulate. Пример это наглядно демонстрирует.

fold_result прекращает итерацию на первом встреченном ошибочном значении. В твоём же примере все ошибочные значения просто игнорируются. Что “наглядно демонстрирует” только то, что эти примеры не эквивалентны, о чём я собственно и говорил.

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

Это ты расскажи, какие исключения бросаются из функции без noexcept.

Любые

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

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

Вручную пробрасывать исключения с потерей информации. Тоже вариант. А если без потери информации об исключении?

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

А если подтянута, то придётся очень сильно напрячься, чтобы пробросить исключение в итератор без потери информации. Я даже не представляю как. Скажем спасибо разработчикам С++ за throw «blablabla»;

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

Мы же говорили о том, что как сделать так, чтобы не пришлось менять код accumulate и код замыкания, но при этом итерация просто останавливалась на первой ошибке. Вот посредством такой обертки, но с потерей информации об ошибке.

Если же мы хотим чего-то другого, то придется менять сигнатуру замыкания, чтобы она получала какой-нибудь variant<T,exception_ptr>. Ну и сделать такую обертку над итераторами, чтобы operator* возвращал этот самый variant.

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

fold_result прекращает итерацию на первом встреченном ошибочном значении.

Что не соответствует общепринятому значению .fold().

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

old_result прекращает итерацию на первом встреченном ошибочном значении.

Что не соответствует общепринятому значению .fold().

Зато соответствует поставленному условию, чего не скажешь о твоём коде. А fold_result можно и по-другому назвать, если тебе это спать спокойно мешает.

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

Это да. Но следы этого идут в такую далекую историю, что многих из LOR-чан тогда еще и на свете не было :)

К счастью, очень редко приходилось видеть подобные библиотеки.

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

Ну а какая практическая польза от «знания» набора возможных исключений?

Обычная польза от контракта, проверяемого компилятором. И warm fuzzy feeling, конечно.

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

Обычная польза от контракта, проверяемого компилятором.

Ну вот опыт Java показывает, что польза крайне сомнительная. Особенно в том, что касается обобщенного программирования.

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

Обычная польза от контракта, проверяемого компилятором.

Ну вот опыт Java показывает, что польза крайне сомнительная.

Опыт Java относится к checked exceptions и Java. Распространять его на возвращаемые значения и Rust в лучшем случае рано. В Go возврат ошибок вполне работает, а это гораздо ближе к подходу Rust.

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

Тип исключения, выбрасываемого checked функцией в Java, это тип сумма всех исключений, выбрасываемых вызываемыми функциями. И изменить это никак нельзя. Отсюда и все проблемы. Result намного гибче.

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

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

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

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

Нормального ответа не услышал.

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

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

Или это то самое, из-за чего нужно переходить с C++ на Rust?

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

Блин, ты сам сейчас сетовал, что библиотека может выкинуть исключение типа int. Из-за этого в общем случае пробросить исключение в то же замыкание в fold'е без потери информации невозможно.

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

Ты уводишь разговор в сторону.

Я говорю о Rust.

Я просил тебя рассказать, какая польза от знания типов выбрасываемых исключений?

В Rust нет исключений. А если ты не видишь пользы от знания типа возвращаемого значения, разговаривать не о чем.

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

Это показывает, что все приспособились обходить эти грабли. Граблей от этого меньше не становится.

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

Я сказал, что при написании exception safe кода знание конкретного типа исключения практически не нужно.

Отдельный геморрой можно получить, если подтянуть в проект библиотеку, которая бросает что-то отличное от std::exception-наследников. А можно и не получить. Как правило проблемы встречаются где-то на верхнем уровне, где стоит catch(const std::exception&).

При этом таких нестандартных библиотек очень мало.

Так что в обычной жизни с такими вещами не сталкиваешься от слова совсем. И знание точного типа исключения для написания exception safe кода практически не нужно.

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

какая польза от знания типов выбрасываемых исключений?

в сторону HKT, логики второго порядка и контрактного программирования с инвариантами классов и пред/постусловиями методов (и rescue/retry, восстанавливающим инварианты методов). сюда же про зависимые типы на лямбда-кубе (опять же, для model checking).

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

знание конкретного типа исключения практически не нужно.

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

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

Я говорю о Rust.

Ты говорил, что в C++ если у функции нет noexcept, то она может бросить что угодно, а может и не бросить. И это плохо.

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

Приведи, пожалуйста.

В Rust нет исключений. А если ты не видишь пользы от знания типа возвращаемого значения, разговаривать не о чем.

См. выше о чем речь. Речь не о том, чтобы похерить возвращаемое значение. А о том, что видя прототип T accumulate(begin, end, init, functor) ты видишь столько же информации, как и в случае прототипа Result<T,Error> accumulate(begin, end, init, functor).

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

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

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

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

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


Функция и так возвращает результат. Исключение на то и исключение, что результатом не является. Совершенно необязательно помнить «что каждая строчка может выбросить исключение, которое мы где-то вверху ловим, или не ловим». Помнить об этом надо лишь там, где мы хотим это исключение обработать. А вот с твоим подходом, на сколько я его понимаю, мы должны везде проверять, а нет ли в результате ошибки.

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


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

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


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

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


Так ты и по-русски не понимаешь.

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

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

Если ошибку не нужно обрабатывать, то достаточно передать её выше с помощью макроса try! (или оператора `?`, если его стабилизируют). Помнить об этом не надо - компилятор сам напомнит. А в С++ нужно помнить, что через функцию в любой момент может пролететь исключение. Exception safety guidelines придумали не от хорошей жизни.

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

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


fixed

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


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

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

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


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

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

С точки зрения отчистки ресурсов и сохранения инвариантов, между try! и throw разницы что-то не видать.

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

Ты говорил, что в C++ если у функции нет noexcept

Rust 1.9 (комментарий), первый абзац.

Остальное - это (неудачная) попытка объяснить тебе эту простую вещь.

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

Приведи, пожалуйста.

Обработка ошибок, которая зависит от того, какая именно ошибка случилась (не сводящаяся к «напечатать сообщение и сделать rethrow»). Например, делаешь ты что-то с ФС, и вылетает ошибка - если это EACCESS, то приплыли, если ENOSPACE - можно почистить временные файлы и повторить.

Речь не о том, чтобы похерить возвращаемое значение. А о том, что видя прототип T accumulate(begin, end, init, functor) ты видишь столько же информации, как и в случае прототипа Result<T,Error> accumulate(begin, end, init, functor).

Если обе accumulate - на Си++.

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

А в С++ нужно помнить, что через функцию в любой момент может пролететь исключение. Exception safety guidelines придумали не от хорошей жизни.

В этом смысле Си++ и Rust одинаковы. В Си++ нужно помнить об исключениях, в Rust - о панике, а об early return нужно помнить и там, и там.

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

Если обе accumulate - на Си++.

Ну покажи, как бы это было на Rust-е.

Заодно покажи, как бы ты выражал на Rust-е ситуацию с EACCESS/ENOSPACE и т.д.

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

Если ошибку не нужно обрабатывать, то достаточно передать её выше с помощью макроса try! (или оператора `?`, если его стабилизируют). Помнить об этом не надо - компилятор сам напомнит.

И обрамлять каждый такой вызов этим вашим «try!»?

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
    let n = try!(contents.trim().parse::<i32>().map_err(|e| e.to_string()));
    Ok(2 * n)
}

Не помню как в C++, но в Java компилятор тоже напомнит о том, что нужно либо try-catch написать, либо ещё один throws методу добавить.

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

Умные указатели в С++ уже ставятся по умолчанию? Нет, это просто очередной абзац в руководстве «Как писать С++ код, который не падает с сегфолтом, если что-то пойдёт не так».

В Rust'е контроль за освобождением ресурсов обеспечивает компилятор. В С++ - программист. Не забываем, humanum errare est.

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

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

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

В Rust-е уже научились явным образом обозначать места возникновения паник?

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

Ну да C++ ладно, он древний и совместимость с C до сих пор аукается. Можно посмотреть на более современные языки, в которых исключения поддерживаются. Тот же D, который так же позиционируется как конкурент C и C++. Шаблоны, исключения, RAII в полный рост.

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

Не надо о грустном, так все хорошо развивалось до 2007-го года...

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

Ну покажи, как бы это было на Rust-е.

На Rust это было бы так же, но, поскольку это Rust, контракт функции состоит из ее сигнатуры, а не сигнатуры и исключений. Еще end не нужен:

Result<T, IoError> accumulate(iter, init, fn)

(IoError - это небольшое мошенничество, но я его себе прощаю).

Заодно покажи, как бы ты выражал на Rust-е ситуацию с EACCESS/ENOSPACE и т.д.

std::io::Error::raw_os_error

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