#12368 has 3 concrete suggestions for possible solutions (which are
included in your list of 6):
- A FailingReader wrapper that wraps another reader and fails on errors
- A ChompingReader wrapper that "chomps" errors, but stores them so that
they are externally accessible
- Have the lines() iterator itself store the error, so that it can be
accessed after the loop
https://github.com/mozilla/rust/issues/12368
Huon
On 20/02/14 09:50, Kevin Ballard wrote:
On Feb 19, 2014, at 2:34 PM, Lee Braiden <leebr...@gmail.com
<mailto:leebr...@gmail.com>> wrote:
Then we could introduce a new struct to wrap any Reader that
translates non-EOF errors into EOF specifically to let you say “I
really don’t care about failure”.
It sounds like a very specific way to handle a very general problem.
People like (modern, complete) scripting languages because they
handle this sort of intricacy in elegant, ways, not because they
gloss over it and make half-baked programs that don't handle errors.
It's just that you can, say, handle IOErrors in one step, at the top
of your script, except for one particular issue that you know how to
recover from, six levels into the call stack. Exceptions (so long as
there isn't a lot of boilerplate around them) let you do that,
easily. Rust needs a similarly generic approach to propagating
errors and handling them five levels up, whether that's exceptions or
fails (I don't think they currently are flexible enough), or monads,
or something else.
In my experience, exceptions are actually a very /inelegant/ way to
handle this problem. The code 5 levels higher that catches the
exception doesn’t have enough information about the problem in order
to recover. Maybe it just discards the entire computation, or perhaps
restarts it. But it can’t recover and continue.
We already tried conditions for this, which do let you recover and
continue, except that turned out to be a dismal failure. Code that
didn’t touch conditions were basically just hoping nothing went wrong,
and would fail!() if it did. Code that did try to handle errors was
very verbose because conditions were a PITA to work with.
As for what we’re talking about here. lines() is fairly unique right
now in its discarding of errors. I can’t think of another example
offhand that will discard errors. As I said before, I believe that
.lines() exists to facilitate I/O handling in a fashion similar to
scripting languages, primarily because one of the basic things people
try to do with new languages is read from stdin and handle the input,
and it’s great if we can say our solution to that is:
fn main() {
for line in io::stdin().lines() {
print!(“received: {}”, line);
}
}
It’s a lot more confusing and off-putting if our example looks like
fn main() {
for line in io::stdin().lines() {
match line {
Ok(line) => print!(“received: {}”, line),
Err(e) => {
println!(“error: {}”, e);
break;
}
}
}
or alternatively
fn main() {
for line in io::stdin().lines() {
let line = line.unwrap(); // new user says “what is
.unwrap()?” and is still not handling errors here
print!(“received: {}”, line);
}
}
Note that we can’t even use try!() (née if_ok!()) here because main()
doesn’t return an IoResult.
The other thing to consider is that StrSlice also exposes a .lines()
method and it may be confusing to have two .lines() methods that yield
different types.
Given that, the only reasonable solutions appear to be:
1. Keep the current behavior. .lines() already documents its behavior;
anyone who cares about errors should use .read_line() in a loop
2. Change .lines() to fail!() on a non-EOF error. Introduce a new
wrapper type IgnoreErrReader (name suggestions welcome!) that
translates all errors into EOF. Now the original sample code will
fail!() on a non-EOF error, and there’s a defined way of turning it
back into the version that ignores errors for people who legitimately
want that. This could be exposed as a default method on Reader called
.ignoring_errors() that consumes self and returns the new wrapper.
3. Keep .lines() as-is and add the wrapper struct that fail!()s on
errors. This doesn’t make a lot of sense to me because the struct
would only ever be used with .lines(), and therefore this seems worse
than:
4. Change .lines() to fail!() on errors and add a new method
.lines_ignoring_errs() that behaves the way .lines() does today.
That’s kind of verbose though, and is a specialized form of suggestion
#2 (and therefore less useful).
5. Remove .lines() entirely and live with the uglier way of reading
stdin that will put off new users.
6. Add some way to retrieve the ignored error after the fact. This
would require uglifying the Buffer trait to have .err() and .set_err()
methods, as well as expanding all the implementors to provide a field
to store that information.
I’m in favor of solutions #1 or #2.
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev
_______________________________________________
Rust-dev mailing list
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev