On Feb 19, 2014, at 3:40 PM, Jason Fager <jfa...@gmail.com> 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
Rust-dev@mozilla.org
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to