-
Notifications
You must be signed in to change notification settings - Fork 13k
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
print!
macro should flush stdout
#23818
Comments
As a quick survey, standard output is line buffered in C, C++, Python, and Ruby. Go's |
I opened #23823. It's not entirely clear to me that the solution isn't to just update the docs to point out that stdout in unbuffered, but I think at the point where you're invoking the |
Sure, but that's orthogonal, since the underlying fd is not, and writing to it will not emit anything until it's flushed. I'm pretty sure that the correct approach is to merge that patch, but figured it was worth pointing out that updating the docs may be a valid approach too. |
It's not 100% clear to me that this is the behavior that we want. In #23087 it was explicitly removed due to worries about deadlocking. The specific problem of deadlocking can be papered over, but in general APIs tend to work much better over time if they do precisely what you expect, and it may not always be expected that One downside of flushing on I would be fine beefing up the documentation in this regard, of course! |
That's totally reasonable, and mostly what I expected. Do you have a Will update the docs if no one beats me to it. On Saturday, March 28, 2015, Alex Crichton [email protected] wrote:
|
While making the documentation clearer would certainly be helpful, I think Rust is losing ease of use by making auto-flushing more difficult than need be. C++ has |
Could there be new macros for this use case? I'd hate for Rust I/O to be harder to use correctly than C++'s especially in a common learning case. For example, since C++ does flush #include <iostream>
int main() {
std::cout << "Type something: ";
std::string input;
std::cin >> input;
std::cout << input << std::endl;
} Also according to the C standard:
|
I generally really dislike implicit flushing and prefer to flush explicitly. On the other hand, there’s |
The design here is generally mostly about trade-offs. On one hand you have "ease of use" where you don't have to worry about calling For example, what should this code do? let input = io::stdin();
let mut locked = input.lock();
print!("enter input: ");
let mut input = String::new();
try!(locked.read_line(&mut input));
println!("you entered: {}", input); If |
I think you misunderstood what the issue is about: it is only proposed to flush std_out_ after macro_rules! print(…) {
…
} to macro_rules! print(…) {
…
stdout().flush()
} Since let output = io::stdout();
let output = output.lock();
print!("stdout locked"); // deadlock. I’m starting to believe that stabilising |
Hm yes, I think I have misunderstood! There are definitely performance considerations which affect flush-on-all-print semantics as it's not something that other languages tend to do and can greatly hinder various benchmarks. |
I think the crux of this is basically "What is the intent of print!". My While I don't believe it's actually on the table, I would be a stoic -1 to On Mon, Mar 30, 2015 at 1:50 PM, Alex Crichton [email protected]
|
To address the performance considerations, could the |
@tanadeau unfortunately it's a performance concern both attached and not attached to a TTY |
I'm against this. Implicit flushing will degrade performance of programs doing specifically What, for example, do you use for actual text printing of your main output in console programs? I used About buffering: this man mentions the defaults |
Since stdout is line-buffered by default, we need to ensure any pending writes are flushed before exiting. Ideally, this should be enforced by each utility. Since all utilities are wrapped by mkmain, this was a convenient location to enforce this behavior. I previously was handling this on a case-by-case basis. See: rust-lang/rust#23818
Since stdout is line-buffered by default, we need to ensure any pending writes are flushed before exiting. Ideally, this should be enforced by each utility. Since all utilities are wrapped by mkmain, this was a convenient location to enforce this behavior. I previously was handling this on a case-by-case basis. See: rust-lang/rust#23818
Fwiw Ive run into this more than a few times and each time it was confusing as a user. Its the same kind of confusion you'd have if you pushed a print button in your browser and nothing happens. I think part of a compromised solution lies in a more meaningful name. We have buffered readers and writers for the performance mentioned above and do not cause the same kind of confusion because their names reveal their expected behavior. What about a bufprint macro you can call when you want buffering and have print's default behavior be to... print something. |
I just ran into this issue for the first time, and just to give my two cents: I generally agree with what's been said.
At the same time, I think it would be beneficial to have a separate print macro which flushes - |
I've been quite busy lately, but I have a prototype implementation of flushing print macros and an RFC mostly written. I'll try to get it out for review in the next few weeks. If someone wants to help get it out sooner, let me know. |
I believe that (Also, having a |
The macro names I am currently using in my draft RFC are |
My guess is that a large percentage of folks will (or should) read the second edition book to get started. I would recommend changing the chapter two exercise code to use If I were to make a suggestion for a more elegant solution I would go back to @CleanCut's suggestion to add a new macro. However, I would look for something a bit terser. Maybe |
My current partially-finished draft RFC has an |
+1 for a python-style input! macro, which takes care of the typical write-then-read case.
It's worth noting that technically |
I only have a shallow understanding of how flushing works, so please forgive the question. How will people be bitten? My guess:
Is there anything else? These issues seem trivial when I weigh them against the panic and frustration of "I'm printing stuff but it doesn't appear on-screen." The people writing performance-intensive command-line apps can use non-flushing |
What about a printf! macro that prints and then flushes? Without modifying the behavior of the print! macro |
I'd be okay with a macro that guarantees a flush, but I'd be concerned about naming it |
How about |
The main problem about Considering this snippet of code: use text_io::read;
let rect = Rectangle {
length: {
print!("L: ");
read!()
},
width: {
print!("l: ");
read!()
}
}; The expected behaviour is this:
What actually happens is this:
C++ buffers |
Sorry, what are those reasons? It seems that in this particular case a special flush+read function/macro is a good bet, so it can be even part of the |
Having the option to print and flush in one macro, unbounded from needing to also read, seems like a good addition to the language. |
THIS. I am re-reading the book trying to get into Rust again and right at the beginning of the Guessing Game chapter I recalled running into issues with flushing the first time I read the book and used If no changes are going to be made for With that said, I personally think |
Furthermore, most people dislike reading a book (even online) about every detail of the language. I know this is a sensible topic, bringing reactions like "how can you not read the book?" ( Python is pretty much the only other language where the default way of printing doesn't flush at least when input is needed, yet they have the |
In no other programming language that I worked with is that a need. It is merely an "oh, that's cool". Furthermore, Rust breaks an expectation that is fulfilled by other languages: input given without the full output shown is garbage, unwanted input. Here are two examples:
Another question would be why |
This is my personal suggestion to the problem: print!(shouldflush, "{}", args...); being fn main() {
let a = 5;
// Normal printing, as is now
print!("{}", a);
// Some io borrow
// Printing with flushing
print!(shouldflush, "{}", a);
} Maybe other options might be passing a boolean, or |
I am new to Rust and ended up here with this problem. I note that print commands in all languages default to displaying on the screen rather than actually printing anything on the printer. Those days have passed. If I were to name an autoflushing macro, I would call it display! |
what is the difference between |
They are basically the same; |
Just to add my 5 cents, I think
|
As stdout is line-buffered, stdout is not implicitly flushed until a new-line is encountered. This means that the
print!
macro does not act like aprintln!
without the newline as the documentation suggests. To be equivalent, the user must explicitly flush stdout like the following:For easy use of the print macros, the user should not need to know about how I/O flushing works. As such,
print!
should explicitly flush stdout itself.The text was updated successfully, but these errors were encountered: