Комментарии 81
Меня это достаточно сильно огорчает, потому что я не начинаю активно программировать на Rust именно из-за неудобств с обработкой ошибок. Даже достаточно посредственная поддержка со стороны IDE, нестандартный синтаксис и другие мелкие проблемы не останавливают. А теперь, похоже, ждать придется ещё дольше.
+10
На Хабре есть такая статья «Что же там такого тяжелого в обработке исключений C++?». В статье рассказывается про две стратегии обработки исключений, из коей можно сделать выводы, что вне зависимости от выбранного механизма, есть некоторый (малый или умеренный) оверхед.
Не знаю, как обстоят дела с оверхедом механизма ошибок в Rust, но есть подозрение, что их затруднения как раз связаны с желанием имплементировать механизм ошибок, за который не придётся платить в рантайме. Что весьма похвально для системного языка. Вообще, одна из самых лучших вещей в Rust это то, что они по сути на полную катушку используют принцип C++ «вы не платите за то, что не используете», и при этом приправляют его статическими гарантиями.
Короче, поживём увидим. Не взяли в релиз: не хотят уже затягивать с 1.0, потому как давали гарантии по датам. С другой стороны можно получить разброд в коде библиотек, написанных после релиза. В общем, хейтеры найдут к чему прицепиться, а прогрессивному человечеству остаётся просто осознать принятое решение.
Не знаю, как обстоят дела с оверхедом механизма ошибок в Rust, но есть подозрение, что их затруднения как раз связаны с желанием имплементировать механизм ошибок, за который не придётся платить в рантайме. Что весьма похвально для системного языка. Вообще, одна из самых лучших вещей в Rust это то, что они по сути на полную катушку используют принцип C++ «вы не платите за то, что не используете», и при этом приправляют его статическими гарантиями.
Короче, поживём увидим. Не взяли в релиз: не хотят уже затягивать с 1.0, потому как давали гарантии по датам. С другой стороны можно получить разброд в коде библиотек, написанных после релиза. В общем, хейтеры найдут к чему прицепиться, а прогрессивному человечеству остаётся просто осознать принятое решение.
+13
НЛО прилетело и опубликовало эту надпись здесь
Судя по вашему комментарию, вас данная новость сильно расстроила. Если честно, не писал ничего серьёзного на Rust, хотя и балуюсь иногда с ним. Поэтому я немного не в курсе, неужели сейчас обработка ошибок на Rust настолько ужасна, чтобы это стало для вас ключевым фактором?
+1
Я в основном пишу на C#. Я привык к нормальным исключениям, дополнительной информации в них, стек трейсам и общему базовому классу (причём не только для исключений).
Ещё я пишу на С++. Там с исключениями похуже, но всё же терпимо. Именно С++ я хочу заменить на Rust. Отсутствие исключений меня останавливает в первую очередь.
У нас тут 2015 год на носу, в конце концов. Я считаю, что возвращаться на 20 лет назад не стоит, и современные языки программирования должны отличаться от их двадцатилетних предшественников определенным гарантируемым набором фич. Все уже привыкли к классам, вызове функции в виде
А отдельную группу людей, в 2014-м году пишущую прикладные вещи на Си и дарующую нам еженедельно новую уязвимость, я просто не понимаю. Это непрактично, небезопасно и не выгодно.
Ещё я пишу на С++. Там с исключениями похуже, но всё же терпимо. Именно С++ я хочу заменить на Rust. Отсутствие исключений меня останавливает в первую очередь.
У нас тут 2015 год на носу, в конце концов. Я считаю, что возвращаться на 20 лет назад не стоит, и современные языки программирования должны отличаться от их двадцатилетних предшественников определенным гарантируемым набором фич. Все уже привыкли к классам, вызове функции в виде
a f b
(метод), а не f a b
, свойствам, функциям высшего порядка, обобщенным классам, делегатам и, наконец, исключениям. Отказ от этого — это откат на 20 лет назад.А отдельную группу людей, в 2014-м году пишущую прикладные вещи на Си и дарующую нам еженедельно новую уязвимость, я просто не понимаю. Это непрактично, небезопасно и не выгодно.
+6
Я привык к нормальным исключениям, дополнительной информации в них, стек трейсам и общему базовому классу (причём не только для исключений).
То есть речь только о неудобстве отладки?
Ещё я пишу на С++. Там с исключениями похуже, но всё же терпимо. Именно С++ я хочу заменить на Rust. Отсутствие исключений меня останавливает в первую очередь.
C++ — один из моих основных языков. Писал на нём как с исключениями, так и без них (были проекты, где они были отключены и включать их было нельзя). Не сказал бы, чтобы использование исключений что-то так уж кардинально меняло. Наверное на шарпе или расте всё иначе. Можете привести пример, чтобы стало понятно?
+1
Возьмём пример из статьи. Пусть есть стек из 50 функций, на дне которого находится способная провалиться функция
Мне кажется очевидно, какие варианты выигрывают.
div
. Давайте рассмотрим варианты обработки этой ошибки.- Обработка а-ля Option из Rust. Если что-то не получилось, каскадом выходим сразу из всех 50 функций (немного кода в каждой функции).
На вершине стека вы получаете молчаливый отказ. Надо объяснять почему это так плохо? - Обработка а-ля Result из Rust с автоматическим конвертированием Err (проброс через try! + интероперации, немного кода в каждой функции, куча кода за пределами функций для интеропераций).
На вершине стека вы в лучем случае получаете DivisionByZero. Полностью бесполезный, у вас там снизу 50 функций. - Обработка а-ля Result, но с ручным конвертированием в Error и заполнением данными (огромная куча кода везде).
На выходе вы получите дебаг информацию, зависящую от того, как вы написали обработку ошибок в каждой из 50 функций. - Без обработки ошибок, но с одним throw именно в том месте, где может быть ошибка — в div. А может и без throw, пусть язык этим занимается.
На вершине стека вы получаете полный стек трейс, сообщение об ошибке и какие-то дополнительные данные, ничего для этого не сделав. - Оборачивание исключений в этих 50 функциях в нужных местах.
Получаете production-ready код с морем дебаг информации, обернув в нужном месте исключения.
Мне кажется очевидно, какие варианты выигрывают.
+9
Без обработки ошибок, но с одним throw именно в том месте, где может быть ошибка — в div. А может и без throw, пусть язык этим занимается.
На вершине стека вы получаете полный стек трейс, сообщение об ошибке и какие-то дополнительные данные, ничего для этого не сделав.
Оборачивание исключений в этих 50 функциях в нужных местах.
Получаете production-ready код с морем дебаг информации, обернув в нужном месте исключения.
То есть я не ошибся и основное применение — удобный сбор информации для отладки? А на вершине стека просто отправка этой информации куда-либо?
+1
На вершине стека вы в лучем случае получаете DivisionByZero. Полностью бесполезный, у вас там снизу 50 функций.Там есть возможность с помощью макросов
file!
и line!
получить номер строки в файле. Просто напишите свой try!
, который будет не просто возвращать ошибку, а ещё и добавлять к ней информацию о том, где она пробрасывалась. Это вариант 3, но «кучу кода» пишет компилятор. Эти же макросы могут быть использованы и в месте генерации ошибки.Локальные переменные вы, конечно, не получите (а, может, я просто плохо знаю макросы Rust). Но это всё же лучше, чем стандартный вариант.
0
А какой, простите, смысл делать относительно сложную систему типов и потом одним махом компрометировать ее введением исключений?
Checked-исключения не предлагать, вспомним Java.
Checked-исключения не предлагать, вспомним Java.
0
А что подразумевается под компрометацией?
0
Возможность исключения никак не выражается в сигнатуре функции, соответственно тайпчекер спокойно пропустит код, который упадёт в рантайме. С этой точки зрения Result кажется более подходящим средством обработки ошибок.
+3
А чем типизированный Result принципиально отличается от checked-исключений в Java, которые вы просили «не предлагать»?
Собственно, строго типизированные исключения не являются чем-то таким особенным, если понять, что это просто монада, и в любом языке, где есть средства для работы с монадами, автоматический проброс и гарантированная обработка с полной строгой типизацией реализуются, по сути, автоматически.
Исключения в Java тоже можно рассматривать в качестве такой монады, которая насильно засунута в каждый закоулок языка (т.е. условно говоря — каждое выражение в Java на самом деле имеет не тип T, а Result<T, ExceptionList>). Проблема с ними там в том, что в Java убогие дженерики, которые вообще никак не покрывают throws, что не позволяет объявлять higher-order functions с корректной сигнатурой («я бросаю все, что бросает переданная мне функция, плюс X, минус Y»). Это, кстати, пытались прикрутить в Project Lambda на ранних этапах, но после радикального упрощения оно пошло под нож.
Собственно, строго типизированные исключения не являются чем-то таким особенным, если понять, что это просто монада, и в любом языке, где есть средства для работы с монадами, автоматический проброс и гарантированная обработка с полной строгой типизацией реализуются, по сути, автоматически.
Исключения в Java тоже можно рассматривать в качестве такой монады, которая насильно засунута в каждый закоулок языка (т.е. условно говоря — каждое выражение в Java на самом деле имеет не тип T, а Result<T, ExceptionList>). Проблема с ними там в том, что в Java убогие дженерики, которые вообще никак не покрывают throws, что не позволяет объявлять higher-order functions с корректной сигнатурой («я бросаю все, что бросает переданная мне функция, плюс X, минус Y»). Это, кстати, пытались прикрутить в Project Lambda на ранних этапах, но после радикального упрощения оно пошло под нож.
+1
У меня немного опыта с Java, но мне всегда сhecked-исключения казались отличной идеей. Как я понимаю, вы относитесь к ним довольно негативно. Если не трудно, расскажете почему?
+1
Я к ним не отношусь никак, ибо на Java не пишу уже пару лет.
Checked-исключения в теории однозначно лучше unchecked. Но у исключений в принципе очень плохо с composability (кстати, как это лучше по-русски сказать?). То, что в функциональном стиле можно записать в виде непрерывной цепочки вызовов, в Java превратится в лестницу вложенных try-catch. Косвенный довод в пользу моего мнения — наличие в Scala типа Try[T], который как раз превращает код, бросающий исключения в код, возвращающий результат в виде алгебраического типа данных.
Checked-исключения в теории однозначно лучше unchecked. Но у исключений в принципе очень плохо с composability (кстати, как это лучше по-русски сказать?). То, что в функциональном стиле можно записать в виде непрерывной цепочки вызовов, в Java превратится в лестницу вложенных try-catch. Косвенный довод в пользу моего мнения — наличие в Scala типа Try[T], который как раз превращает код, бросающий исключения в код, возвращающий результат в виде алгебраического типа данных.
0
Трассировку стека Rust умеет выдавать.
0
А что происходит, например, при делении на ноль? Крашится?
0
Да, происходит panic таска (для искуственного создания есть макрос
panic!
). Если это основной таск, то приложение закрывается.0
Если в panic есть полная инфа (место возникновения, stack trace), то больше и не надо.
Тут я кажется понял соображения, которыми руководствовались создатели Rust.
Исключения нужно бросать, но не ловить. Если какой-то процесс падает, пусть падает полностью. Если программист не знает точно, что может пойти не так, он может обернуть выполнение в таск. Это заставит не использовать исключения в рабочих сценариях — только если на самом деле произошла невосстановимая ошибка и надо перейти к следующему элементу, залогировав ошибку.
Тот же пример с делением — не стоило вычислять функцию вслепую, не сделав анализ всех ситуаций. Если на верхнем уровне программист знает, когда должно произойти деление на 0, можно не вызывать функцию. А если не знает — вызов чреват ошибками. Вдруг что-то пошло непредвиденно, но исключение не выпало.
Тут я кажется понял соображения, которыми руководствовались создатели Rust.
Исключения нужно бросать, но не ловить. Если какой-то процесс падает, пусть падает полностью. Если программист не знает точно, что может пойти не так, он может обернуть выполнение в таск. Это заставит не использовать исключения в рабочих сценариях — только если на самом деле произошла невосстановимая ошибка и надо перейти к следующему элементу, залогировав ошибку.
Тот же пример с делением — не стоило вычислять функцию вслепую, не сделав анализ всех ситуаций. Если на верхнем уровне программист знает, когда должно произойти деление на 0, можно не вызывать функцию. А если не знает — вызов чреват ошибками. Вдруг что-то пошло непредвиденно, но исключение не выпало.
+1
Разве что не хватает «finally», чтобы при возникновении panic вышестоящие уровни могли правильно де-инициализироваться.
А локальные переменные выше по стеку будут в этом случае правильно уничтожены? Если да, всё вообще хорошо.
А локальные переменные выше по стеку будут в этом случае правильно уничтожены? Если да, всё вообще хорошо.
0
НЛО прилетело и опубликовало эту надпись здесь
Как ни странно, finally в Rust есть. Только немного громоздкий.
+1
Странненькая ссылка )
+1
Ой, сорри) не знаю, как так получилось)
Вот правильная: doc.rust-lang.org/std/finally/
Вот правильная: doc.rust-lang.org/std/finally/
+1
Это заставит не использовать исключения в рабочих сценариях — только если на самом деле произошла невосстановимая ошибка и надо перейти к следующему элементу, залогировав ошибку.Во-первых, восстановиться после panic нельзя, только из другого таска. Во-вторых, не всегда можно отдать код в отдельный таск, есть требовательные к, например, производительности места. В-третьих, писать код с вездесущим try и проверкой на 0 перед делением — слишком дорого. Выше я написал комментарий с возможными сценариями.
0
Если это основной таск, то приложение закрывается.
Не основной, а последний. В Rust нет основных тасков как в Go, все треды равноправны.
0
Серебряной пули не вышло… ну да ладно. На низком уровне исключений сейчас и так нет, далеко не все реализации C++ имеют поддержку исключений, вот я ими и не пользуюсь переносимости ради.
setjmp — эпохальный костыль, вместе с возвращением NULL. В Rust оно хоть выглядит приличнее и проверяется на этапе компиляции.
setjmp — эпохальный костыль, вместе с возвращением NULL. В Rust оно хоть выглядит приличнее и проверяется на этапе компиляции.
+2
НЛО прилетело и опубликовало эту надпись здесь
Ну что, язык Go с его “return nil, err” передаёт горячий привет своему «убийце»:)
+8
Да, забавно смотрится, как абсолютно такой же подход к обработке ошибок просто оброс Rust-specific синтаксисом.
Цитирую документацию:
Цитирую документацию:
// This is a three level match pyramid!
match checked::div(x, y) {
Err(why) => fail!("{}", why),
Ok(ratio) => match checked::ln(ratio) {
Err(why) => fail!("{}", why),
Ok(ln) => match checked::sqrt(ln) {
Err(why) => fail!("{}", why),
Ok(sqrt) => sqrt,
},
},
}
они будто бы даже гордятся тем, что можно городить пирамидку из вызовов и проверок их Result на ошибки.+4
Хаскелисты смотрят на это с недоумением.
Обработка ошибок по своей природе — вещь монадическая, неужели нельзя навертеть пару макросов, чтобы реализовать монадический бинд? Что-то вроде (с синтаксисом rust знаком весьма поверхностно):
В haskell подобные цепочки разворачиваются в такой же код, что и в вашем примере.
Отсутствие исключений, честно говоря, вообще не огорчает.
Обработка ошибок по своей природе — вещь монадическая, неужели нельзя навертеть пару макросов, чтобы реализовать монадический бинд? Что-то вроде (с синтаксисом rust знаком весьма поверхностно):
checked::div(x, y) >>= |ratio| checked::ln(ratio) >>= |ln| checked::sqrt(ln)
В haskell подобные цепочки разворачиваются в такой же код, что и в вашем примере.
Отсутствие исключений, честно говоря, вообще не огорчает.
+9
Я думаю учитывая функциональные возможности Rust что-то такое предполагалось.
0
Вообще вся эта конструкция на расте записывается так:
Либо, если хочется именно пайпа, то делается примерно как в хаскелле:
let ratio = checked::div(x, y).unwrap();
let ln = checked::ln(ratio).unwrap();
let sqrt = checked::sqrt(ln).unwrap();
Либо, если хочется именно пайпа, то делается примерно как в хаскелле:
checked::div(x, y).and_then(|ratio| checked::ln(ratio).and_then(|ln| checked::sqrt(ln).unwrap()))
+1
НЛО прилетело и опубликовало эту надпись здесь
А чего я, простите, должен добиться? В оригинальном коде используется проверка с вызовом удалённого сейчас макроса fail!, заменой которого в данной ситуации и является panic!, поэтому unwrap делает ровно то, что нужно.
0
Полагаю, что в оригинальном коде fail! исключительно для примера (неудачного), а суть отрывка как раз в демонстрации возможности не паникуя обрабатывать ошибки через мэтчинг.
0
Разница с монадой в том, что в последней у вас результатом вычисления последовательности выражений будет тоже Result — у которого можно проверить Error. Т.е. это эквивалент плюсового:
Где вы не проверяете отдельно каждый вызов foo, bar и baz на Error, а ловите его один раз при выходе из блока.
try {
foo();
bar();
baz();
} catch (Error) {
...
}
Где вы не проверяете отдельно каждый вызов foo, bar и baz на Error, а ловите его один раз при выходе из блока.
0
Следующий раздел из документации, которую процитировал Xlab, говорит:
Т. е. в тех случаях, когда нужно просто пробросить ошибку наверх, достаточно написать:
И это будет эквивалентно:
Чистый match предполагается применять только в случае окончательной обработки ошибок на верхнем уровне.
Chaining results using match can get pretty untidy; luckily, the try! macro can be used to make things pretty again. The try! macro expands to a match expression, where the Err(err) branch expands to an early return Err(err), and the Ok(ok) branch expands to an ok expression.
Т. е. в тех случаях, когда нужно просто пробросить ошибку наверх, достаточно написать:
let sqrt = try!(checked::sqrt(x));
do_smth(sqrt);
И это будет эквивалентно:
match checked::sqrt(x) {
Err(why) => return Err(why),
Ok(sqrt) => {
do_smth(sqrt);
}
}
Чистый match предполагается применять только в случае окончательной обработки ошибок на верхнем уровне.
+1
А как этот макрос работает? И doc.rust-lang.org/guide-macros.html#motivation, например?
В него do_smth не передаётся никаким образом, вроде, а в развёрнутом коде оно есть.
В него do_smth не передаётся никаким образом, вроде, а в развёрнутом коде оно есть.
0
Ну, макросы в Rust это не макросы из Си, они работают немного по-другому:
http://doc.rust-lang.org/std/macro.try!.html
http://doc.rust-lang.org/std/macro.try!.html
0
Ну, ясное дело. Исходный код я почитал. Передаётся туда одно выражение, по которому и матчится, а do_smth как там оказывается?
0
Он там не оказывается. Макрос
try!
разворачивается в зависимости от аргумента либо в return why
из Err(why), либо в value
из Ok(value). Этот самый value
потом можно чему-то присвоить: let sqrt = try!(checked::sqrt(x));
и уже после этого над ним изобразить do_smth(sqrt);
.+1
Почитал документацию внимательнее, оказалось, я был неправ. Макрос
То есть это:
Развернется в это:
В макросе по привиденной вами ссылке разобраться с текущим уровнем знания
try!
определен следующим образом:macro_rules! try(
($e:expr) => (match $e { Ok(e) => e, Err(e) => return Err(e) })
)
То есть это:
let sqrt = try!(checked::sqrt(x));
do_smth(sqrt);
Развернется в это:
let sqrt = match checked::sqrt(x) { Ok(e) => e, Err(e) => return Err(e) };
do_smth(sqrt);
В макросе по привиденной вами ссылке разобраться с текущим уровнем знания
Rust
'а не могу, извиняйте.+1
Спасибо. Макрос try! оказался простым, а вот реализация biased_match от меня ускользает. Ощущение, что там какой-то хак, потому что прямой разворот макроса выглядит каким-то странным.
0
Если знание английского позволяет, можете заглянуть сюда: www.reddit.com/r/rust/
На этот раздел подписаны 6,5 тысяч людей, в том числе те, кто контрибьютит в Rust (серые и сиреневые бейджи «
Уверен, что с вашим вопросом вам там смогут помочь.
На этот раздел подписаны 6,5 тысяч людей, в том числе те, кто контрибьютит в Rust (серые и сиреневые бейджи «
rust
»), а также сами создатели языка (оранжевые бейджи).Уверен, что с вашим вопросом вам там смогут помочь.
0
Такая возможность существует в виде методов на
Result
и Option
. Кроме того, в коммьюнити языка одна из наиболее желаемых фич — это higher-kinded types, которые открывают дорогу, в том числе, к обобщённым монадам и обобщённым операторам для работы с ними, наподобие do-нотации хаскелля или for comprehensions скалы. К сожалению, в 1.0 этого не будет просто по причине нехватки времени.+1
Гм. В каждой статье про Rust всегда найдётся умник, который сравнит его с Go, но называть его «убийцей» — это пожалуй впервые. Который раз уже вам объясняют: Go не конкурент Rust по-крайней мере в области системного программирования, потому как ни один системщик не станет всерьёз рассматривать в качестве языка разработки язык со сборщиком мусора. Go имеет свою конкретную, вполне узкую область — это язык для написания бэкендов. Rust же позиционируется как системный язык общего назначения, то есть современная альтернатива C/С++.
+17
Как раз наоборот — под каждой статьёй про Go находятся умники, которые начинают рассказывать, какой Go негодный язык, и как всё то, что ужасно в Go (да и во всех остальных языках), будет в Rust-е сделано правильно и шоколадно.
Так что когда оказалось, что Rust, по сути, использует ту же работу с ошибками, что и Go (за которую последнего ругают все кому не лень), то удержаться от иронии было сложно:)
Так что когда оказалось, что Rust, по сути, использует ту же работу с ошибками, что и Go (за которую последнего ругают все кому не лень), то удержаться от иронии было сложно:)
-7
Что ж все нервные такие… Ну извините, если обидел.
-1
Здесь тред немного политический, хоть и хабр и в не политики. Так что оставляя здесь комментарий не в пользу Rust вы рискуете быть неправильно понятым, так как все нейтрально мыслящие иронию поняли как надо, мне кажется :)
Меня тоже достали сравнения, но блин, это как в ситуации с Android vs iOS — первые сравнивают и критикуют, вторые берут и пользуются. Меня интересует расклад дел и прогноз на будущее, так что я много читаю мнений. И вот почему-то «нелюбителям» Go не лень каждый раз сравнивать его с Rust и прочими хаскелями, подчеркивая ничтожность, почему бы не заметить здесь обратное наблюдение? Что как ни крути, а один из главнейших минусов разработчики «по-настоящему правильного» языка взяли да оставили без новизны подхода :)
Меня тоже достали сравнения, но блин, это как в ситуации с Android vs iOS — первые сравнивают и критикуют, вторые берут и пользуются. Меня интересует расклад дел и прогноз на будущее, так что я много читаю мнений. И вот почему-то «нелюбителям» Go не лень каждый раз сравнивать его с Rust и прочими хаскелями, подчеркивая ничтожность, почему бы не заметить здесь обратное наблюдение? Что как ни крути, а один из главнейших минусов разработчики «по-настоящему правильного» языка взяли да оставили без новизны подхода :)
Go имеет свою конкретную, вполне узкую область — это язык для написания бэкендовОдин брякнул и все повторяют из уст в уста, что значит для бекэндов? Нет, я не спорю, что в realtime задачах при ограниченном наборе ресурсов или при большом количестве данных требуется специализированный подход, но Go привязывать к «backend» смысла нет. Вот я бы поспорил, удобнее ли на Rust писать GUI программы, чем на Go.
-2
НЛО прилетело и опубликовало эту надпись здесь
Вообще, строго говоря, в go можно отключить gc и освобождать память руками (неявно — зануляя слайсы и т.д., через задницу, в общем =)
-1
НЛО прилетело и опубликовало эту надпись здесь
Исключения, кроме оверхеда, плохи еще тем, что добавляют неявные побочные эффекты, а в Rust все-таки есть установка на явность.
Кстати, интересный вопрос: а каким образом можно на двух стульях усидеть — и явность сохранить, и избавиться от вложенных конструкций обработчиков ошибок в цепочках вызовов? И без монадических хитростей, в идеале :)
Кстати, интересный вопрос: а каким образом можно на двух стульях усидеть — и явность сохранить, и избавиться от вложенных конструкций обработчиков ошибок в цепочках вызовов? И без монадических хитростей, в идеале :)
+2
Ну и отлично!
+1
А мне не совсем понятен подход с не owner str и мутабельным owner String (ака StringBuilder).
Также интересна судьба абстрактных типов, например
Также интересна судьба абстрактных типов, например
fn get_iter(&self) -> Iterator<i64>;
.0
Общее мнение насчёт abstract return types — они нужны, но пока можно потерпеть. Соответствующий RFC был закрыт с комментарием, что он нуждается в переработке. Скорее всего, после 1.0 к нему вернутся.
0
Не совсем понял, если функция возвращает значение типа Result<f64, MathError>, как в примере из статьи, то можно ли «замапить» его на другую функцию с помощью map/flatMap?
Грубо говоря, вот что-то похожее на такой пример будет работать в Rust?
fn div(x: f64, y: f64) -> Result<f64, MathError>
fn scale(n) -> Result<f64, MathError>
div(1, 2) map scale(100)
Грубо говоря, вот что-то похожее на такой пример будет работать в Rust?
fn div(x: f64, y: f64) -> Result<f64, MathError>
fn scale(n) -> Result<f64, MathError>
div(1, 2) map scale(100)
0
Извините, совершенно непонятно, почему подобная новость заслуживает отдельной статьи. В Rust есть исключения в смысле stack unwinding — это макрос
RFC по вашей ссылке — это предложение добавить в язык удобный способ пропагации ошибок, похожий на исключения, но не несущий их проблем, потому что этот способ всегда можно переписать через match/return. Фактически, это синтаксический сахар. Он не подразумевает какое-то разворачивание стека и обработку, ничего того, чего нельзя сделать прямо сейчас.
Ну и если на то пошло, то этот конкретный RFC всего лишь отложили до после 1.0, потому что к 1.0 его просто не успели бы реализовать достаточно качественно. Как тут уже сказали, 1.0 — это не конец развития, а только его начало.
panic!()
. Да, такие «исключения» нельзя ловить, но это трудно сделать кроссплатформенно и чревато небезопасностью работы с памятью, поэтому в Rust так делать нельзя.RFC по вашей ссылке — это предложение добавить в язык удобный способ пропагации ошибок, похожий на исключения, но не несущий их проблем, потому что этот способ всегда можно переписать через match/return. Фактически, это синтаксический сахар. Он не подразумевает какое-то разворачивание стека и обработку, ничего того, чего нельзя сделать прямо сейчас.
Ну и если на то пошло, то этот конкретный RFC всего лишь отложили до после 1.0, потому что к 1.0 его просто не успели бы реализовать достаточно качественно. Как тут уже сказали, 1.0 — это не конец развития, а только его начало.
+1
Кстати в довольно используемом в последнее время языке Objective-C приблизительно та же ситуация с исключениями. Они как бы в языке есть, но используются исключительно для runtime error ситуаций, когда нужно записать что-то в лог и умереть.
Все фреймворки построены вокруг возвращения ошибки через возвращаемое значение или параметр-указатель.
При этом я не могу сказать, что за несколько лет написания кода под iOS мне это как-то сильно мешало.
Все фреймворки построены вокруг возвращения ошибки через возвращаемое значение или параметр-указатель.
При этом я не могу сказать, что за несколько лет написания кода под iOS мне это как-то сильно мешало.
+1
Мы пишем в функциональном стиле на F# и сознательно отказались от исключений в пользу возвращаемого типа Choice (по сути тот же Result в Rust). Если результатом функции может оказаться ошибка, то это видно из её сигнатуры, код становиться более явным.
+3
Если результатом функции может оказаться ошибка, то это видно из её сигнатуры, код становиться более явным.
Может быть я задам глупый вопрос, но всё-таки. Вот у нас есть задача: гарантированно обрабатывать ошибки, возвращаемые из функции. В разных языках есть похожие методы её решения: Result/Choice/Maybe и т. п. Но почему никто не делает нормальные checked exceptions? Чем эта концепция хуже опционального типа для отлова ошибок?
0
А есть какое-нибудь волшебное место, где разработчики Rust последовательно обосновывают решения по дизайну языка? Взвешивают за и против различных вариантов? Это был бы просто кладезь. Заглянул в дев-блог, но там как-то пусто.
+1
Есть репозиторий, где публикуются все предложения по внесению изменений в язык (RFC), и там же и обсуждаются.
github.com/rust-lang/rfcs
Есть протоколы встреч, на которых принимаются решения, включать то или иное предложение в язык или нет.
github.com/rust-lang/meeting-minutes
Есть ещё форум, на котором люди периодически обсуждают предложения перед их публикацией, но там относительно много шума и мало чего доходит даже до стадии RFC.
discuss.rust-lang.org/
github.com/rust-lang/rfcs
Есть протоколы встреч, на которых принимаются решения, включать то или иное предложение в язык или нет.
github.com/rust-lang/meeting-minutes
Есть ещё форум, на котором люди периодически обсуждают предложения перед их публикацией, но там относительно много шума и мало чего доходит даже до стадии RFC.
discuss.rust-lang.org/
+3
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
В Rust 1.0 исключений не будет