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

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

Ну так это же прямой путь к граблям checked exceptions из Java. Если fn захочет возвращать еще и SecurityError, то что тогда?

std::io::Error::raw_os_error

std::system_error?

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

Еще end не нужен:

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

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

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

Ну так это же прямой путь к граблям checked exceptions из Java

Я пришел из Си. Опыта с java мало и страшные истории о checked exceptions для меня просто фольклор. В чем там грабли - перемапить одно исключение в другое?

Если fn захочет возвращать еще и SecurityError, то что тогда?

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

std::system_error?

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

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

Опыта с java мало и страшные истории о checked exceptions для меня просто фольклор. В чем там грабли - перемапить одно исключение в другое?

Как раз проблема именно в этом. Какой-нибудь умник определяет интерфейс и декларирует, что некий метод getContent бросает FileNotFoundException. Тебе приходится делать реализацию этого метода, но у тебя нет никаких файлов, у тебя, например, есть работа с сетью. И там свои исключения, но никак не FileNotFoundException. И у тебя остается два варианта — любо бросать unchecke exception, либо мапить свои исключения в FileNotFoundException.

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

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

Ты имеешь в виду, что эту учебную задачу ты можешь решить и по-другому?

Нет, я о том, что если ты в Rust-е делаешь что-то вроде:

let r : Result<T, Error> = some_method();
match r {
  case std::io::Error => ... 
}
То это мало чем отличается от:
try {
  some_method();
}
catch( const std::system_error & x ) { ... }

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

И у тебя остается два варианта — любо бросать unchecke exception, либо мапить свои исключения в FileNotFoundException.

Или же определить ещё один тип ошибок и перестать писать костыли.

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

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

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

Какой-нибудь умник определяет интерфейс и декларирует, что некий метод getContent бросает FileNotFoundException. Тебе приходится делать реализацию этого метода, но у тебя нет никаких файлов, у тебя, например, есть работа с сетью.

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

Ты имеешь в виду, что эту учебную задачу ты можешь решить и по-другому?

Нет

Хм. Ну то есть ты используешь исключение так, как я бы использовал ошибочную часть Result/ Да, так можно. А если ошибочная часть Result - sum type, то разные catch выполнят pattern matching. Ты делаешь Rust из Си++, с throw вместо return.

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

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

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

Какой-нибудь умник определяет интерфейс и декларирует, что некий метод getContent бросает FileNotFoundException.

В io::Error это предусмотрено. В него можно засунуть всё, что реализует трейт Into<Box<Error>>.

То это мало чем отличается от:

Как я уже 3-й раз пишу, обычно (я написал уже прилично кода на Rust) достаточно try!, который преобразует тип ошибки, возвращаемый some_function, в тип ошибки, возвращаемой вызывающей функцией. Если разбираться в типах ошибок не нужно (а нужно их логировать), то достаточно использовать Box<std::Error>.

В общем, бессмысленный спор. На практике, использование Result, никаких особых проблем не создаёт.

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

это какой-то особый юзкейс

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

Кто-то пишет фреймворк и говорит: вот вам интерфейс, сделайте свой класс, который его реализует, создайте объект этого класса и отдайте в наш фреймворк. Но при этом он (автор фреймворка) думает, что все реализации интерфейса будут такими же, как та демо-реализация, которую он сделал. Отсюда и список исключений на методов интерфейса.

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

Что мешало автору фрейворка ограничится более общими классами исключений? А фиг его знает. Может не подумал, может ошибся, может он сначала конкретный класс делал, а потом из класса выделили интерфейс и делали это уже совсем другие люди.

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

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

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

На практике, использование Result, никаких особых проблем не создаёт.

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

Равно как и у исключений есть своя цена.

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

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

Кто-то пишет фреймворк

Я и говорю - фольклор об ужасах checked exceptions относится к взаимодействию с фреймворками.

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

Да почему? Ну, придется определить ремап ваших специфических исключений в исключения, которые имел в виду автор фреймворка. В чем ужас?

Блин, напиши развернутый комментарий

Я переписал комментарий.

Ибо в упор не вижу, чем то, что ты написал про исключения, отличается от Rust-овских кодов возврата

В том и суть, что они исполняют очень схожую роль. А если так, то зачем исключения?

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

какие цели преследуют ярые «заменяторы Си»?!

Писать на чем-то менее убогом.

Да пишите на чем хотите!

Между кончиной Cyclone и появлением Rust надежды на это не было.

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

Как раз проблема именно в этом. Какой-нибудь умник определяет интерфейс и декларирует, что некий метод getContent бросает FileNotFoundException. Тебе приходится делать реализацию этого метода, но у тебя нет никаких файлов, у тебя, например, есть работа с сетью. И там свои исключения, но никак не FileNotFoundException. И у тебя остается два варианта — любо бросать unchecke exception, либо мапить свои исключения в FileNotFoundException.

Классический пример неправильной архитектуры. Если интерфейс разрабатывался для работы лишь с файлами, то зачем пытаться использовать его для работы с нефайлами? А если нужно работать не только с файлами, то интерфейс должен декларировать не FileNotFoundException, а IOException.

Нормальные разработчики просто ставили throws Exception и не парились.

Вот как раз такое нормальный разработчик врядли напишет. Обычно так делают быдлокодеры.

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

Я и говорю - фольклор об ужасах checked exceptions относится к взаимодействию с фреймворками.

Современно программирование, за пределами отдельных ниш (вроде embedded) — это сплошное взаимодействие с фреймворками.

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

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

Я переписал комментарий.

Да, теперь понятно, что мы говорим об одних и тех же вещах.

В том и суть, что они исполняют очень схожую роль. А если так, то зачем исключения?

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

Ну и толку от кодов возврата, если ни Rust, ни Go, которые специально отказались от исключений, вынуждены использовать паники? ;)))

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

Совершенно согласен. Неправильная архитектура. Но бывает, что она дана свыше и ничего с этим уже не поделать. Автор мог описать IOException вместо FileNotFoundException. Но не написал. Более того, со временем может выясниться, что и IOException не совсем в тему.

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

Вот как раз такое нормальный разработчик врядли напишет.

Ну и как бы написал нормальный разработчик?

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

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

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

В данном случае IOException, мы же уже выяснили.

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

Ну и толку от кодов возврата, если ни Rust, ни Go, которые специально отказались от исключений

Толк от кодов возврата в том, чтобы 1) у функции был ровно один канал возврата значений (проверяемый компилятором на общих основаниях) 2) обработка была единообразной (match вместо match и catch) 3) эффективности (возврат значений эффективнее запуска исключений).

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

вынуждены использовать паники? ;)))

Я не претендую на понимание того, как паника должна использоваться в современном Rust, но, ИМХО, это такой несмертельный assert - т.е. вещь для сигнализации о внутренних ошибках программы.

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

В случае раста RAII — неотъемлемая часть языка даже без паник. В случае го, соглашусь.

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

Ты забыл ешё одно маленькое преимущество: Result можно передавать между тредами.

А в Си++ нельзя передавать std::exception?

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

3) эффективности (возврат значений эффективнее запуска исключений).

Тут нужно смотреть. В Rust-овом Result<int, Error> значение Error будет передаваться как? Через указатель на динамически созданный объект?

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

Совершенно согласен. Неправильная архитектура. Но бывает, что она дана свыше и ничего с этим уже не поделать. Автор мог описать IOException вместо FileNotFoundException. Но не написал. Более того, со временем может выясниться, что и IOException не совсем в тему.

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

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

exception_ptr вполне себе хорошо передается между тредами, на этом базируется работа promise/future.

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

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

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

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

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

В Rust-овом Result<int, Error> значение Error будет передаваться как? Через указатель на динамически созданный объект?

Error вообще трейт, ЕМНИП, так что через указатель. А в Result<T, IoError> - по значению, как было бы и в Си++.

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

Error вообще трейт, ЕМНИП, так что через указатель.

Ну тогда нужно с профайлером смотреть. Т.к. в случае с постоянными match-ами на кодах возврата у тебя всегда будут накладные расходы. Если исключения бросаются часто, то может быть, match-и выйдут дешевле (но опять же, как часто в Result-ах будут хранится Error-ы).

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

`std::exception` можно. Но это не Result, и обработка ошибок зависит от того, откуда данные — из этого треда или другого.
В случае Result'а не важно откуда он, в случае исключений всё чуть-чуть сложнее.

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

Ну тогда нужно с профайлером смотреть

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

Если исключения бросаются часто, то может быть, match-и выйдут дешевле

«Может быть»? Возврат значения - это просто инструкция ret, запуск исключения - вызов функции раскрутки стека, цену создания ошибочного объекта предполагаем одинаковой. По-моему, всё очевидно.

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

`std::exception` можно. Но это не Result, и обработка ошибок зависит от того, откуда данные — из этого треда или другого

Я таки не вижу разницы в передаче между нитями Result или std::exception.

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

По-моему, всё очевидно.

Ты когда в последний раз с профайлером сидел? Обычно профайлер показывает, что очевидные вещи не самые правильные.

Возврат значения — это не просто ret, особенно если возврат идет через стек. Плюс сразу после возврата у тебя будет условная инструкция, что не есть хорошо.

Так что тут лучше говорить про результаты конкретных замеров.

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

В случае Result ты просто получаешь или значение, или ошибку. В случае исключения ты пробуешь получить ошибку, если получаешь её, перебрасываешь, чтобы блок try-catch выше её обработал, если нет, то получаешь значение.

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

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

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

ты прикинь в госконторах такая херня в 90% случаев.

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

Его идея владений оказалась очень интересной.

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

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

Возврат значения — это не просто ret, особенно если возврат идет через стек

Я же говорю - стоимость создания запускаемого или возвращаемого объекта полагаем равной.

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

Я сам за активное использование АлгТД вместо исключений из-за

у функции был ровно один канал возврата значений (проверяемый компилятором на общих основаниях)

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

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

если речь не об embedded и реальном времени, конечно

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

tailgunner ★★★★★
()

Грустно наблюдать, что Rust начинает обрастать легаси. Сейчас из-за специализации `to_string()` vs `to_owned()`, потом будет `try!` vs `?` и т.д.

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

Сама их природа предполагает, что это что-то редкое (ну, мб во всяких питонах, где итераторы вызывают исключения при завершении это не так, но не в крестах же)

Ещё 5 лет назад в С++ не было удобного способа возвратить несколько значений из функции (tuple), и до сих пор нет аналога Result. Так что исключения - единственный удобный способ сигнализировать что, что-то пошло не так. Считать удобным костыли, вроде

auto result;
if (do_smth(/*out*/ &result)==S_OK) {
 // Используем result
} else {
 // Не забываем, что result тут неопределён
}
// Не забываем, что тут result может быть неопределён
я отказываюсь.

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

Да сам Result сделать в сях/крестах очевидно просто — через тегированное объединение. Проблема скорее в том, что работать с этим не удобно без паттерн-матчинга.

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

Сейчас из-за специализации `to_string()` vs `to_owned()`

Эти функции предназначены для разных задач, но так получилось, что для &str они делают одно и то же.

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