Disclaimer: please forgive my ignorance if I miss something. I’m not experienced with Rust yet.
Today, it’s common to find code like
extern crate term;
fn main() {
let mut t = term::stdout().unwrap();
t.fg(term::color::GREEN).unwrap();
(write!(t, "hello, ")).unwrap();
t.fg(term::color::RED).unwrap();
(writeln!(t, "world!")).unwrap();
t.reset().unwrap();
}
As one might learn pretty quickly, unwrap()ing a None returned by term::stdout() will lead to failure of task. This is, of course, specified in docs. But it’s certainly not obvious that this is not a “safe” operation — it may lead to “crash”. Not “hard” crash, because it will be handled by Rust runtime. It produces error about unwrapping None. But it’s a crash nevertheless. And it happens due to several reasons:
- Absence of warnings from compiler that
.unwrap() is essentially a pattern match w/o “catch-all” case. We do get warnings when not all variants of enum are handled, so why skip it here?
- Usage in official documentation — in example code like that of
term. Conditions programmer to accept it as something normal.
Let’s face it — unwrap() of Option<_> is awful hack. It’s convenient, I know — but it’s the sort of convenience we disdain JavaScript and PHP for. I also understand that one is extremely likely to use unwrap() in closures because “heck, I only need to filter/map/reduce stuff, I don’t want my closure to spend 5 lines!”. Programmer uses it there and then forgets about it. Voila — safety is needlessly violated.
I think a programmer should be forced to actively discard any failure condition. It makes for explicit decision making about not handling an error.
In Rust, in it’s present state, unwrap() is the easiest and simplest way to Get Things Done. This shortcut will be taken by many and many people who will then later complain about Rust not being secure despite claiming itself “preventing almost all crashes”.
I have at least two ideas about it:
- Introduce attribute, like
#[unsafe] or something, indicating that
the function will panic!() on some inputs. The compiler would
then issue warnings (or errors) about usage of such functions. And
it probably can be extended to everything that can call panic!()
inside (although I’m very much not sure about this last point. It might turn out we need to warn about 99% of standard library).
- Promote safer error handling in documentation more. All the
lazy
unwrap()s can be replaced with proper idiomatic error handling code.
I’m eager to hear opinion of more experienced rustaceans.