Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't panic when println!() fails #24821

Closed
lilyball opened this issue Apr 25, 2015 · 7 comments
Closed

Don't panic when println!() fails #24821

lilyball opened this issue Apr 25, 2015 · 7 comments
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@lilyball
Copy link
Contributor

Right now print!() and println!() explicitly panic when they get an error writing to stdout. This is undocumented. It's also surprising, partially because printing to stdout is not usually considered "critical" functionality for a program, and partially because all precedent I'm aware of in other languages for "print this thing to stdout" does not abort if the print fails.

Anyone printing information to stdout that is "critical", such that the program should not continue if the write failed, should be using write!() or writeln!() (or one of the io::Write methods) in order to handle the error (which could just be calling .unwrap() to panic if the write failed). But I fully expect that the vast majority of code using println!() is not printing something that is so critical that the program should refuse to continue if the print fails, and as such should simply ignore any errors instead of panicking. Ultimately, println!() is the "convenience" way to print informative stuff to stdout, and panicking on EPIPE is not very convenient.

There was some discussion a year ago on #13824 that floated the idea of ignoring the error, but it seemed fairly inconclusive. And another ticket #14505 shows that rustc reports an ICE when invoked as rustc --version | false (due to false terminating without reading stdin).

Conceptually, I believe that println!(...) should be equivalent to let _ = writeln!(io::stdout(), ...), although in practice it won't be because std::io still has the task-local stdout replacement functionality (used by libtest).

/cc @alexcrichton

@lilyball
Copy link
Contributor Author

I don't believe this should be considered a breaking change. It's undocumented behavior, so we're making no guarantees at all about what happens when stdout has been closed, which means nobody should be relying on this behavior. Anyone that does need to abort if the write fails should be using something like writeln!(io::stdout(), ...).unwrap() already.

@bluss
Copy link
Member

bluss commented Apr 26, 2015

Edit: This was a thought from Python's evolution of print from version 2 to 3; unlike Python, in Rust, println! is almost never used for file output; programs instead use write!/ln! for that. That means: it is not as important to handle errors with println!.


I want to think about what a typical Rust program's evolution is going to be. A mature program is going to want to handle this error case gracefully, does that mean that at some point of the development of a typical rust program it's going to have to replace all its println!() calls with more complicated writeln! invocations? (Probably using an internal macro to keep sanity.)

I think that if println!() ends up being this obsolete feature of a maturing Rust program, eventually becoming useless, then the design is wrong.

@alexcrichton
Copy link
Member

I thought I commented to this effect elsewhere, but I haven't found an example of any language that ignores all errors by default from printing. Everything is "ignored" in C because no one checks the return value of printf, which would be akin to Rust returning a Result from print!

@steveklabnik
Copy link
Member

Triage: @rust-lang/libs, sounds like you need to decide if this is change you'd want to make.

@alexcrichton alexcrichton added I-nominated T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Jan 3, 2017
@alexcrichton
Copy link
Member

Discussed during libs triage today our decision was to leave the behavior as-is. Changing this behavior is likely an RFC-scale change, so it wouldn't want to be tracked here as well.

@JimFawcett
Copy link

JimFawcett commented Apr 25, 2020

std::io::stdout().write_all has same panic behaviour, as demonstrated by this code:
let invalid: &[u8] = &[0xED, 0xA0, 0x80];
let rslt = std::io::stdout().write_all(invalid);
This panics, does not return error rslt, when run on windows, e.g., write_all does not honor its signature contract: fn write_all(&mut self, buf: &[u8]) -> Result<()>

@maver1ck
Copy link

@alexcrichton
Any new thougts about this in 2020 ?

@rust-lang rust-lang locked and limited conversation to collaborators Jun 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants