Extremely pre-RFC: `eprintln!`

The ?-in-main discussion reminded me of another way in which Rust currently makes the easy thing be the wrong thing, if you are writing command-line programs: the easiest way to emit non-fatal error messages is println!, but that sends them to stdout, which is not where error messages should go. panic! does the right thing (and thus also unwrap, expect, assert!, etc) but those are all (a) fatal and (b) properly used only for conditions that indicate a bug. The most straightforward way to write diagnostics to stderr is

writeln!(io::stderr(), "out of cheese error").unwrap();

which is significantly more typing in itself, requires you to use std::io::Write, and doesn’t have println!'s defensive measures against being called at an awkward moment.

The simplest thing we could possibly add to fix this problem would be an eprintln! macro, which would be exactly the same as println! except that the output goes to stderr instead of stdout. (It’d be more natural to call it error! instead, but the log crate already snagged that one.) (I’m not sure whether we want eprint! as well — progress messages also belong on stderr, and often don’t want a newline, but it might turn out to be just as easy to keep using write! for those.)

All of the documentation should also be updated to make it clear that it is inappropriate to use println! for error messages.

26 Likes

Yes please. I define this macro manually in many crates.

I think I’d personally be on board with this too. I define eprintln! in almost every single main crate I’ve ever written. I use that exact name as well.

I don’t care as much about eprint!. I don’t think it’s commonly used enough to justify adding it, but I could see adding it for consistency reasons with print!.

1 Like

Here’s one more reason for eprintln, in addition to “stderr is the proper stream for diagnostics”: eprintln! is very useful for printf debugging when stdout is meaningful.

6 Likes

+1, though I previously came up with the name println_err! for this. At least I find the e prefix a bit too cryptic / non-obvious.

2 Likes

What about changing println! to accept an optional first argument?

println!(stderr, "out of {} error", "cheese");
println!(stdout, "a {} error happened", "cheese");
println!("a {} error happened", "cheese");
5 Likes

@djc I agree eprint(ln) is cryptic, but I think print(ln)_err is too long; the nice thing about a one-letter prefix is it’s really fast to type.

@ekuber How would that be different from writeln! then?

If we’re tossing out name ideas, how about errln!()

8 Likes

For what it’s worth this macro is available in crates.io. https://crates.io/crates/errln

2 Likes

I wonder if this is necessary. Maybe more convenient logging is really what people want and/or need. Being able to just write:

error!("Your disk {} is fscked.", disk_name);

without adding any libraries or importing anything or having to do anything beyond just typing that would be the correct solution. I think the only reason eprintln! would be useful is for short quick programmes where you just want to write a quick script to do something and don’t want to go to all the trouble of finding out that there’s a log crate, adding dependencies, downloading crates, adding extern crate etc.

I’ve long wanted this in the standard library. It seems rather harmless to me. Many projects already define eprint! and eprintln! manually (or an equivalent). I don’t find the names cryptic either. I would argue that there is a need for it outside of logging, e.g. for debugging or for user interaction. As such logging frameworks do not supersede eprintln!. Also, I’d rather we stayed away from names like error! because printing on stderr can be part of a normal run. In particular, eprint! can be useful if you expect input from the user.

1 Like

Formal RFC now posted.

println!(stderr, "out of {} error", "cheese");

stderr wouldn't be a struct that implements Write, but rather a literal parsed by the macro. By making it that way, the only thing your code would need to add to send to stderr instead of stdout is that first argument. But then again that might not be desirable, and too much magic by half.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.