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

RFC: add eprint(ln)! #1869

Merged
merged 2 commits into from
Mar 14, 2017
Merged

RFC: add eprint(ln)! #1869

merged 2 commits into from
Mar 14, 2017

Conversation

zackw
Copy link
Contributor

@zackw zackw commented Jan 23, 2017

@jonas-schievink
Copy link
Contributor

Rendered

@jethrogb
Copy link
Contributor

I think there should be both eprintln! and eprint!, using those names.

I think the final name shouldn't focus too much on the “error” part. Yes, the output stream is called stderr, but it really just means “out-of-band” messages that are not part of the regular output.

@comex
Copy link

comex commented Jan 23, 2017

However, errln has the advantage of having its purpose immediately apparent, whereas eprintln could be anything (extended? enhanced? extra?).

@ExpHP
Copy link

ExpHP commented Jan 23, 2017

Adding only eprintln without eprint would present an immediate challenge to anyone migrating stderr output away from write{,ln} and/or print{,ln}. I migrated such a piece of code yesterday after seeing the pre-RFC:

for dla_step in 0..NPARTICLE {
    err!("Particle {:8} of {:8}: ", dla_step, NPARTICLE);

    // ... long, time consuming computation ...

    errln!("({:8.6}, {:8.6}, {:8.6})  ({:5?} ms)",
        (pos.0).0, (pos.1).0, (pos.2).0, timer.last_ms()
    );
}
Particle        0 of      200: (0.512422, 0.523495, 0.481173)  ( 1184 ms)
Particle        1 of      200: (0.521386, 0.543189, 0.473058)  ( 1202 ms)
Particle        2 of      200: (0.498974, 0.538118, 0.488474)  ( 1146 ms)
Particle        3 of      200: (0.546846, 0.565138, 0.500004)  ( 1171 ms)
Particle        4 of      200: _

That said, this kind of usage of stderr also conflicts with its typical designation as "a safe place to dump stuff"; if I added debugging output to methods called during that computation, it would mess up my nice output.

In this sense, I would almost see a lack of eprint! as a sort of statement about how stderr is intended to be used. As to whether I agree with that statement, I'm not sure.

@strega-nil
Copy link

I'm of the opinion that, whatever we call it, we should add it. I've reimplemented these macros in far too many Rust programs.

@BurntSushi
Copy link
Member

I would also like to have this. Like @ubsan, I've written this macro a gagillion times.

Some lightly held opinions:

  1. I like eprint and eprintln the best.
  2. I would be disappointed if we wound up with an underscore in the name.
  3. I could live without eprint, but there's really not much downside to adding it for consistency with print.

@liigo
Copy link
Contributor

liigo commented Jan 25, 2017

errprint/errprintln is another alternativea. err is more meaningful than e.

Update: Rust should avoid introducing excessively abbreviated names, such e vs error, especially for non-core names.

@BurntSushi BurntSushi self-assigned this Jan 25, 2017
@joshtriplett
Copy link
Member

On the name bikeshedding: I feel like err or errln seem too likely to conflict with non-printing-related things, and they don't make their purpose as clear. 👍 to eprint! and eprintln!. (Also, I like that these start with a different letter than println! does, which makes them easily differentiable at a glance.)

@Havvy
Copy link
Contributor

Havvy commented Jan 25, 2017

I would rather see it be err_println. eprintln starts looking really esoteric (in the same way as C's function names).

There's also a consistency or learning issue. We don't use e to mean error anywhere else in the stdlib. This makes an ad hoc naming scheme that is only used for two macros, adding to the cognitive load needed to learn the language.

What does the stdlib use for errors right now? Whatever it is, we should align the name with that.

@zackw
Copy link
Contributor Author

zackw commented Jan 25, 2017

My objection to println_err! (it's enough longer and harder to type than println! that people will be discouraged from using it even when they should) applies equally to any other name with an underscore in it. The exclamation point is already one too many uses of the shift key; let's not add more.


It will, however, be necessary to add text to the reference manual and
especially to the tutorials explaining the difference between "primary
output" and "status reports", so that programemrs know _when_ to use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: programemrs

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, thank you.

@jplatte
Copy link
Contributor

jplatte commented Jan 25, 2017

I like @Havvy's suggestion of err_println from a readability perspective, and removing the underscore would negate that IMHO. But I can also see the problem with having an underscore in the name.

I think I'm slightly in favor of err_println over eprintln though, because I personally only have very few such print-to-stderr statements in my programs, to handle errors propagated through Results from inside the program logic.

@petrochenkov
Copy link
Contributor

🚲 I like eprintln!/eprint! specifically (as written in the RFC) because most of the time I use them for "printf debugging" and they need to be quickly typable and won't stay in the code for long 🚲

@ticki
Copy link
Contributor

ticki commented Jan 25, 2017

I dislike this strongly, for this reason:

You aren't supposed to use print/eprint. It is computationally expensive (locking a mutex = atomic operations) and unnecessary most of the time (i.e. you can do let stdout = io::stdout(); let stdout = stdout.lock(); and only lock the mutex once). This makes it a pretty bad habit, and adding eprint!() will only make that more common.

I think print was a mistake, but it's not revertible, because it is used so much, but adding eprint is like digging the hole deeper, IMO.

@BurntSushi
Copy link
Member

@ticki Every command line program I've ever written has never needed to care about the performance of writing to stderr. Conversely, almost every command line program I've written writes to stderr at some point---whether it's a warning, or debug message or an error---and this macro makes this a little more convenient. Seems like a nice trade off to me.

I'm sympathetic to println! being a footgun because I have written programs where use of println! causes it to slow down. I think it is a potential stumbling block for newcomers. But that ship has sailed and I don't think the presence of eprintln! makes it worse.

@eddyb
Copy link
Member

eddyb commented Jan 25, 2017

FWIW it might be a better idea to go with the log crate, except that is too verbose by default.

@sfackler
Copy link
Member

Logging is pretty orthogonal to output designed for consumption by an end user.

@ticki
Copy link
Contributor

ticki commented Jan 25, 2017

@BurntSushi

I can't say my experiences are the same. If you log extensively, you can easily severely slow down the program, whereas using write means that you won't need to lock a mutex for updating the cache.

Moreover, I would say that just throwing out some logs into stderr is, well, hacky. There is no leveling, prefixes, etc., yet this macro gives a high-level "feel", when that's clearly not the case. So I am concerned if it will cause a reduction in use of third-party logging crates, which are more idiomatic.

That being said, this macro can be useful for debugging, but even then you rarely need to filter between stderr and stdout when you debug.

@strega-nil
Copy link

strega-nil commented Jan 25, 2017

@ticki It's pretty common for me to use eprintln in order to have both normal output in the course of the program, and println debugging, because I need to be able to do >/dev/null (and stderr still goes out to the terminal).

@joshtriplett
Copy link
Member

My most common use case for eprintln! would be error messages, not logging. For general-purpose logging, I'd use a structured logging mechanism.

@BurntSushi
Copy link
Member

BurntSushi commented Jan 25, 2017

There's nothing hacky about printing an error message to stderr without log leveling.

@theduke
Copy link

theduke commented Jan 26, 2017

Please don't call it eprintln / eprint, that's a really esoteric/cryptic name.

These would all be better, with my personal (weak) preference towards println_err

  • printerrln
  • errln
  • errprintln
  • println_err
  • printlnerr

@seanmonstar
Copy link
Contributor

Out of all the suggestions, I still prefer one from the internals thread:

println!(stderr, "this happened: {}", err);

Adding a variant to the macro that can be either stderr or stdout, to specify.

@joshtriplett
Copy link
Member

At the risk of further bikeshedding: I prefer the forms that start with something other than print, which makes it easier to distinguish them at a glance.

@seanmonstar That looks appealing, but seems difficult to implement in a robust way. Do you intend stderr as a pseudo-keyword in that statement, or as an object? If the latter, what object with what type, and can you pass an arbitrary object of that type? And if you can pass an arbitrary object of that type, you then effectively have an overloaded function implemented as a macro; can that function still identify mistaken usage with a non-literal format string?

@Kimundi Kimundi added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Jan 26, 2017
@iamcodemaker
Copy link

Bikeshed: I prefer eprintln!(). It's concise and similar enough to println!() to be relatively discoverable. You only have to learn it once, so I think it should be easy to type and remember vs optimizing for discoverabability.

@dpc
Copy link

dpc commented Jan 27, 2017

eprintln!(...) is a bit unclear at first, but only takes one web search to decipher it, and afterwards it's obvious and doesn't hurt the eyes in any way. Plus I think stderr has the same rank as stdout so deserves similar treatment: it's own macro. println!(stderr, ...) is not really cutting it (I would still macro it myself in my code).

@cristicbz
Copy link

So, I'm not going to disturb the consensus
-- @nikomatsakis

@matthieu-m
Copy link

I fully second @dpc here. No matter the name we'll need to get used to it anyway, so I don't see much point in bikeshedding it to death.

Let's just make it obvious that it's about printing to stderr.

@k3d3
Copy link

k3d3 commented Mar 12, 2017

One vote for eprintln!()

@zackw
Copy link
Contributor Author

zackw commented Mar 12, 2017

@carols10cents

I would love if someone who feels strongly about this could read through the second edition of the book and file an issue or PR for all the cases that should change.

I will make time to do that if no one beats me to it. Where can I find the publication schedule for the book, so I can know when it needs to happen by?

@kennytm
Copy link
Member

kennytm commented Mar 12, 2017

Proposal Pros Cons
eprint[ln]! Short Cryptic
error[ln]! Clear All good names are taken by log already 😡
print[ln]_err! Descriptive Underscore
print[ln]err! No underscore Long
errprint[ln]! Doesn't start with "p" Long, and flipped word order
stderr_print[ln]! Very descriptive Very long
print[ln]!(stderr) Similar to fprintf Magical
alert[ln]! Specific No this name is for the GUI message box
write[ln]!(stderr())? Status quo Status quo

Here let me propose two more bike-shed colors 🚴‍♀️🚴.

  1. Since the macro in this RFC is proposed for status reports, why not report[ln]!?

    reportln!("out of cheese error: {}", 42);
  2. The main problems of the status quo write[ln]!(stderr(), "help").unwrap() are:

    • stderr(), it is a function call, function call gives an impression of being expensive. All other languages provide stderr as a constant or property.
    • .unwrap() written by user, 'nuff said.
    • use std::io::stderr;, you need to import a module, importing a module gives an impression of bloating the program.
    • use std::io::Write;, but Write appears nowhere in the call, that adds extra cognitive load to connect the dots.
    • LOCAL_STDERRstderr() (though I think it's not a real motivation)

    So what if we:

    • Put STDERR to std::io that deref() to LOCAL_STDERR (similar for STDOUT and STDIN), and use it in prelude, and
    • Provide a macro that simply .unwrap()/.expect() the result of write[ln]!?
    fprintln!(STDERR, "out of cheese error: {}", 42);
Color Pros Cons
report[ln]! Short and descriptive It is not clear we are printing to stderr
fprint[ln]!(STDERR) Similar to fprintf Could cause new users to adapt bad practice in writing to files without error checking; Need extra items in prelude; Long

I am actually skeptical that we cannot use error[ln]! or warn[ln]! due to conflict with logging crates, because #1561 has been merged.

#![feature(use_extern_macros)]

macro_rules! vec {
    ($a:tt) => { "no I'm not a vec :p" }
}

fn main() {
    println!("{:?}", vec!(4));
    println!("{:?}", std::vec!(4));
}
// std::vec! is fine, so why not std::error!?

BTW, if users of most other languages can live without a dedicated print-to-stderr function, I don't see how we are escalating to a crisis here 😄. I don't hear people saying Python / Go / C# / Swift have bad ergonomics because you don't have a simple function to write to stderr.

Rust print[ln]! "eprint[ln]!" write[ln]!(f)
C printf fprintf(stderr) fprintf(f)
C# Console.Write[Line] Console.Error.Write[Line] f.Write[Line]
C++ std::cout << std::cerr << f <<
D writef[ln] stderr.writef[ln] f.writef[ln]
Go fmt.Printf fmt.Fprintf(os.Stderr) fmt.Fprintf(f)
Haskell print hPrint stderr hPrint f
Java System.out.print[ln] System.err.print[ln] f.print[ln]
JavaScript console.[debug/log/info] console.[warn/error]
Lua print / io.write io.stderr:write f:write
PHP echo / print error_log fwrite(f)
Python print print(file=sys.stderr) print(file=f)
Ruby p / puts warn f.write
Swift print ¯\_(ツ)_/¯ (or NSLog) print(to: &f)

@ExpHP
Copy link

ExpHP commented Mar 12, 2017

LOCAL_STDERR ≠ stderr() (though I think it's not a real motivation)

Eh? To me this is the primary motivation! The inability of tests to capture stderr is a massive pain in the behind and leaves me constantly sprinkling around println!s that shouldn't exist!

...yet by that same token, I still ultimately agree with your conclusion. There should be more ways to write capturable output than through a macro; since macros cannot be passed around like files can, and are impossible to abstract over except through more macros. (well, okay, you can do some amount of abstraction with callbacks, but only so much!)


To be honest, I'm not sure I understand why rust's std{out,err}() don't return the local variants to begin with. But of course, I am coming from the (very different) mindset of python, where sys.{stdout,stderr,stdin} can be easily swapped out by simple assignment. (the global streams, if one really needs them, remain available at sys.__stdout__)

@ghost
Copy link

ghost commented Mar 12, 2017

I am actually skeptical that we cannot use error[ln]! or warn[ln]! due to conflict with logging crates, because #1561 has been merged.

And in the discussion in #1561, one concern was about spurring use of the macro import/export system and demonstrating it was understandable and manageable. This seems like a perfect job for that (and I'm a fan of this syntax).

@carols10cents
Copy link
Member

@carols10cents

I would love if someone who feels strongly about this could read through the second edition of the book and file an issue or PR for all the cases that should change.

I will make time to do that if no one beats me to it. Where can I find the publication schedule for the book, so I can know when it needs to happen by?

Thank you @zackw! Basically as soon as this stabilizes... we don't have any hard dates yet, it's just "as soon as everything gets done". See all the states the chapters have to go through and which chapter is in which state (be sure to scroll to the right), chapters 2, 3, 4, and 6 are supposed to be pretty much "frozen" right now with only small changes (I hope this to be a small change) since they'll be going through layout soon.

@suhr
Copy link

suhr commented Mar 12, 2017

I was about to propose report[ln]! too.

@vi
Copy link

vi commented Mar 13, 2017

report[ln] idea is like alert[ln] idea version 2.

@vi
Copy link

vi commented Mar 13, 2017

Can we reuse log's macro names in a way that connecting #[macro_use] extern crate log automatically redirects the stderr console output to logs?
Some macros (for no-newline printing/logging) may even be added to log to maintain symmetry.

@liigo
Copy link
Contributor

liigo commented Mar 14, 2017

CAUTION
There is a very weird thing in this RFC: many people ask for a very short (and cryptic) name.
This is not common in the community.

We may create very short name, but only for very useful use cases. Per kennytm's comment above, many other languages don't have short name for this use case (i.e. writing to stderr).

stderr is already a double-abbreviated name: standard=>std, error=>err. I don't think it can be even crazily shorten as e. eprintln is a bad & cryptic name.

@dpc
Copy link

dpc commented Mar 14, 2017

@liigo A program should print only a direct result to stdout, and errors, status updates, warnings to stderr. Since usually there's only one place when the result is printed out, and many, many potential errors that can happen along the way, code printing to stderr is actually way more common than one printing to stdout. At least if you want to do stuff with best practices in mind. Because of that people don't want it to be too noisy and cumbersome to type. I'd say that if it wasn't a breaking change, I wouldn't mind println to print go to stderr in the first place, and println_stdout be stdout version.

@alexcrichton
Copy link
Member

Ok the libs team convened today and we discussed this RFC. Overall there definitely seems to be broad agreement to the functionality of these macros and the question was the name. Of the many many names proposed here we've decided to stick with the original proposal, eprint and eprintln.

Thanks again for the RFC @zackw!

@alexcrichton
Copy link
Member

Tracking issue: rust-lang/rust#40528

@alexcrichton alexcrichton merged commit c53d19e into rust-lang:master Mar 14, 2017
frewsxcv added a commit to frewsxcv/rust that referenced this pull request May 11, 2017
Add `eprint!` and `eprintln!` macros to the prelude.

These are exactly the same as `print!` and `println!` except that they write to stderr instead of stdout.  Issues rust-lang#39228 and rust-lang#40528; previous PR rust-lang#39229; accepted RFC rust-lang/rfcs#1869; proposed revision to The Book rust-lang/book#615.

I have _not_ revised this any since the original submission; I will do that later this week.  I wanted to get this PR in place since it's been quite a while since the RFC was merged.

Known outstanding review comments:

* [x] @steveklabnik requested a new chapter for the unstable version of The Book -- please see if the proposed revisions to the second edition cover it.
* [x] @nodakai asked if it were possible to merge the internal methods `_print` and `_eprint` - not completely, since they both refer to different internal globals which we don't want to expose, but I will see if some duplication can be factored out.

Please let me know if I missed anything.
frewsxcv added a commit to frewsxcv/rust that referenced this pull request May 11, 2017
Add `eprint!` and `eprintln!` macros to the prelude.

These are exactly the same as `print!` and `println!` except that they write to stderr instead of stdout.  Issues rust-lang#39228 and rust-lang#40528; previous PR rust-lang#39229; accepted RFC rust-lang/rfcs#1869; proposed revision to The Book rust-lang/book#615.

I have _not_ revised this any since the original submission; I will do that later this week.  I wanted to get this PR in place since it's been quite a while since the RFC was merged.

Known outstanding review comments:

* [x] @steveklabnik requested a new chapter for the unstable version of The Book -- please see if the proposed revisions to the second edition cover it.
* [x] @nodakai asked if it were possible to merge the internal methods `_print` and `_eprint` - not completely, since they both refer to different internal globals which we don't want to expose, but I will see if some duplication can be factored out.

Please let me know if I missed anything.
@SRGOM
Copy link

SRGOM commented Jul 21, 2017

I know this is a done deal but I'd like to very briefly present my thoughts against it-

Given that stdin/stdoout/stderr are unix file descriptors, including this in standard rust library with very specific use is not a "rustic" way of handling things. I personally think the right way would be that we have multiple streams: Out, trace, debug, warn, error and at the start of a program the runtime initializes (or user manually) each based on what file descriptors are provided by the OS/shell. println! would just be an alias to streamln!( 1, ... ), and errln! to streamln( 2, ... ), traceln!( 3, .. ) (Or we could start over and give them better nubers, out -> 1, trace -> 2, debug -> 3).

So on windows console, where only one stream is available, all these would go to 1. On Unix, which guarantees stdout and stderr, all but "println!" would direct to 1 and others to 2.

I'm not trying to start a flame war and I'm typing this on Unix myself but let's face it, these streams were designed when there was no GUI. The reason rust works is because rust has thrown out all "conventional" wisdom and starts with 0 baggage. I think a 0 baggage here would be having an option to have multiple streams.

I haven't given too many details/some inconsistent details but I can flesh out more in the off chance you guys might be interested in thinking about it.

@dpc
Copy link

dpc commented Jul 21, 2017

@SRGOM: I've seen this in Powershell, and I dislike it. It really complicates things, for no good reason. stderr and stdout are meant to be outputs, not for logging levels. Rarely any program produces more than one actual output. The stderr is a complication so that there's a stream that is not an output that was intended, but something else. "something else" could mean different things: typically errors, or progress information. From the perspective of different programs, there's rarely any need to route different logging levels to different places, so putting them in different streams is not useful at all.

@zackw zackw deleted the eprintln branch July 27, 2017 21:25
@zackw zackw restored the eprintln branch July 27, 2017 21:26
@Centril Centril added A-macros-libstd Proposals that introduce new standard library macros A-input-output Proposals relating to std{in, out, err}. labels Nov 23, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-input-output Proposals relating to std{in, out, err}. A-macros-libstd Proposals that introduce new standard library macros final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. T-libs-api Relevant to the library API team, which will review and decide on the RFC.
Projects
None yet
Development

Successfully merging this pull request may close these issues.