Thinking about this a bit more, I think that another solution would be:
7 - Update lines() to return an Iterator<IoResult> and then create an
iterator wrapper that fails on any error except for EOF. I think by using
an extension method, the syntax could be:
fn main() {
for line in io::stdin().lines().fail_on_error() {
print!("received: {}", line);
}
}
Which I don't think is too bad. Importantly, it makes it explicit at the
call site what the desired behavior is while also making lines() behave
like all other IO-related methods do.
So, I now favor of either doing something like this or removing it. I
posted more on https://github.com/mozilla/rust/issues/12368.
-Palmer Cox
On Wed, Feb 19, 2014 at 7:37 PM, Kevin Ballard <[email protected]> wrote:
> On Feb 19, 2014, at 3:40 PM, Jason Fager <[email protected]> wrote:
>
> Can you point to any scripting langs whose lines equivalent just silently
> ignores errors? I'm not aware of any; even perl will at least populate $!.
>
>
>
> No, because I typically don't think about errors when writing quick
> scripts. If the script blows up because I had a stdin error, that's fine,
> it was never meant to be robust.
>
> I just commented on #12368 saying that now I'm leaning towards suggestion
> #2 (make .lines() fail on errors and provide an escape hatch to squelch
> them). This will more closely match how scripting languages behave by
> default (where an exception will kill the script).
>
> I opened https://github.com/mozilla/rust/issues/12130 a little while ago
> about if_ok!/try! not being usable from main and the limitations for simple
> use cases that can cause. Forgive a possibly dumb question, but is there a
> reason main has to return ()? Could Rust provide an 'ExitCode' trait that
> types could implement that would provide the exit code that the process
> would spit out if it were returned from main? IoResult's impl would just
> be `match self { Ok(_) => 0, Err(_) => 1 }` and your example would look like
>
> fn main() -> IoResult<~str> {
> for line in io::stdin().lines() {
> print!("received: {}", try!(line));
> }
> }
>
>
> There is no precedent today for having a function whose return type must
> conform to a trait, without making the function generic. Furthermore, a
> function that is generic on return value picks its concrete return type by
> the type constraints of its call site, rather than by the implementation of
> that function. I also question whether this will work form an
> implementation standpoint. Today the symbol for the main() function is
> predictable and is the same for all main functions. With your suggested
> change, the symbol would depend on the return type. I don't know if this
> matters to rustc; the "start" lang item function is passed a pointer to the
> main function, but I don't know how this pointer is created.
>
> But beyond that, there's still issues here. Unlike in C, a Rust program
> does not terminate when control falls out of the main() function. It only
> terminates when all tasks have ended. Terminating the program sooner than
> that requires `unsafe { libc::abort() };`. Furthermore, the main() function
> has no return value, and does not influence the exit code. That's set by
> `os::set_exit_status()`. If the return value of main() sets the error code
> that will overwrite any error code that's already been set.
>
> Perhaps a better approach is to define a macro that calls a function that
> returns an IoResult and sets the error code to 1 (and calls libc::abort())
> in the Err case, and does nothing in the Ok case. That would allow me to
> write
>
> fn main() {
> abort_on_err!(main_());
>
> fn main_() -> IoResult<()> {
> something_that_returns_io_result()
> }
> }
>
> ---
>
> While writing the above code sample, I first tried actually writing the
> read_line() loop, and it occurs to me that it's more complicated than
> necessary. This is due to the need for detecting EOF, which prevents using
> try!(). We may actually need some other macro that converts EOF to None,
> returns other errors, and Ok to Some. That makes things a bit simpler for
> reading, as I can do something like
>
> fn handle_stdin() -> IoResult<()> {
> let mut r = BufferedReader::new(io::stdin());
> loop {
> let line = match check_eof!(r.read_line()) {
> None => break,
> Some(line) => line
> };
> handle_line(line);
> }
> }
>
> Still not great, but at least this is better than
>
> let line = match r.read_line() {
> Ok(line) => line,
> Err(IoError{ kind: EndOfFile, .. }) => break,
> Err(e) => return Err(e)
> };
>
> -Kevin
>
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
>
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev