You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 a println! without the newline as the documentation suggests. To be equivalent, the user must explicitly flush stdout like the following:
use std::io::prelude::*;use std::io;fnmain(){print!("Type something: ");
io::stdout().flush().ok().expect("Could not flush stdout");// Read stdin, etc.}
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.
As a quick survey, standard output is line buffered in C, C++, Python, and Ruby. Go's Printf buffers output and writes it to an unbuffered stdout. Java doesn't document what it does, but System.out appears to autoflush.
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 print*! machinery you're sufficiently far from the OS that you probably just do want some output to appear in the terminal.
Reacted by nightpool, Riccardo Paolo Bestetti, Ian Douglas Scott, Sam Claus, friguron, Adam, davawen, jthulhu, Vijay Ramamurthy, Martin Nordholts and 1 more
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 print! flushes the output buffer.
One downside of flushing on print! would be that any form of "maximal buffering" when redirected to a TTY would be lost. For example C performs much more buffering when stdout is redirected than when it is to a console. This means that simple benchmarks which print information will be much slower in Rust than in comparison with others (due to the frequent flushing).
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
citation about the c buffering though? That wasn't be belief and I'd love
to read more.
It's not 100% clear to me that this is the behavior that we want. In #23087#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 print! flushes the output buffer.
One downside of flushing on print! would be that any form of "maximal
buffering" when redirected to a TTY would be lost. For example C performs
much more buffering when stdout is redirected than when it is to a console.
This means that simple benchmarks which print information will be much
slower in Rust than in comparison with others (due to the frequent
flushing).
I would be fine beefing up the documentation in this regard, of course!
—
Reply to this email directly or view it on GitHub #23818 (comment).
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 std::unitbuf to making auto-flushing simple in cases like prompts and progress bars. This at least makes it so that users don't need to call flush() explicitly after every call.
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 cout when cin is read, the following works fine there but the equivalent doesn't for Rust:
At program startup, three text streams are predefined and need not be opened explicitly
— standard input (for reading conventional input), standard output (for writing
conventional output), and standard error (for writing diagnostic output). As initially
opened, the standard error stream is not fully buffered; the standard input and standard
output streams are fully buffered if and only if the stream can be determined not to refer
to an interactive device.
Reacted by pasbi, msrd0, Yufan Lou, Luke Hsiao, squirrelyman, Murad, John Kugelman, Ishan Bhargava and Hudson Newey
This means that the print! macro does not act like a println! without the newline as the documentation suggests.
println! macro, on the other hand, does not specify anything about its flushing semantics either. Even the std::io::Stdout doesn’t and totally should.
I generally really dislike implicit flushing and prefer to flush explicitly. On the other hand, there’s write{,ln}!, which does not and can’t assume anything about buffering, so I’m ambivalent about this issue.
I think Rust is losing ease of use by making auto-flushing more difficult than need be.
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 flush(), but on the other hand you have worries about deadlocking, and/or surprising behavior happening behind the scenes. On the other hand you have to write a few more flush calls, but you know precisely what is happening and can avoid situations like deadlocking fairly easily.
If print! were to auto-flush, then it would deadlock the current process because the stdin handle was already locked. The alternative here is adding one call to try!(locked.flush()) right above the call to read_line.
If print! were to auto-flush, then it would deadlock the current process because the stdin handle was already locked. The alternative here is adding one call to try!(locked.flush()) right above the call to read_line.
I think you misunderstood what the issue is about: it is only proposed to flush std_out_ after print! writes to the std_out_. i.e. change
macro_rules! print(…){
…
}
to
macro_rules! print(…){
…
stdout().flush()}
Since print! already takes a lock to write, this change will not introduce any more new cases where it deadlocks. For example snippet below deadlocks currently and will deadlock in all the same cases if we made it to auto-flush.
let output = io::stdout();let output = output.lock();print!("stdout locked");// deadlock.
I’m starting to believe that stabilising Std{in,out,err}::lock was a wrong and hasty move.
I think you misunderstood what the issue is about: it is only proposed to flush stdout after print! writes to the stdout
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
intuition is that it's not intended to be in the critical section, and is
instead meant to be a helper for "make this string appear on stdout", I
could really take or leave whether or not it flushes. That said,
considering that it already traverses all of the formatting machinery
anyway, if it can't deadlock my intuition is that the flush is just one
extra syscall to make this do something more user friendly/intuitive.
While I don't believe it's actually on the table, I would be a stoic -1 to
any suggestion of making all stdout writes autoflush.
I think you misunderstood what the issue is about: it is only proposed to
flush stdout after print! writes to the stdout
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.
—
Reply to this email directly or view it on GitHub #23818 (comment).
Reacted by Rett Berg, Jake Swenson, Nic Hartley and tvallotton
I'd be okay with a macro that guarantees a flush, but I'd be concerned about naming it printf, since that's such a ubiquitous identifier in many other languages for "formatted print"
Reacted by Coleman McFarland, Yari, Nic Hartley, Egor Suvorov, Matej Kormuth, Vlad Frolov, Pavel Hrdina, Joel Hernández, Mubelotix, Stuart Robinson and 5 more
How about flprint!, flprintln! macros? Doing printflln! or printlnfl! would look confusing. Is it a problem if it starts with fl cause that might makes it sound like the flushing happens first?
Reacted by Matej Kormuth, Vlad Frolov, Joel Hernández, manvithn, Stuart Robinson, Stuart C. Robinson, Kenny, Sam Claus and Vasily Sidorov
The main problem about print! not flushing is when combining it with read! from the text_io create.
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:
L: 5
l: 3
What actually happens is this:
5
3
L: l:
C++ buffers std::cout, however it ties it to std::cin so that std::cout is flushed before std::cin reads any data, which solves this problem. This is not possible in this case for obvious reasons, so an alternative (perhaps a flprint! macro as suggested above?) should be found.
This is not possible in this case for obvious reasons
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 text_io crate.
This is not possible in this case for obvious reasons
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 text_io crate.
print! is just a macro for dumping stuff into stdout, and it has no connection to anything else (I would assume). A flush+read fn/macro would unnecessarily do two things in one package, restricting flushing only to the case where a read is required.
Having the option to print and flush in one macro, unbounded from needing to also read, seems like a good addition to the language.
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 print and io::stdout().flush().unwrap() for the guess prompt. This way newbies (like myself) will just grok the rustafarian way to handle line buffered stdin. I'll try to put forth a pull request on the docs if someone has not already tried it.
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 print! instead of println! (so the guess would be on the same line, after a colon). Curiosity lead me here.
If no changes are going to be made for print!, the book should definitely use it and mention the flushing semantics.
With that said, I personally think println! and print! are used for simple logging or when getting input from the user 90% of the time. Someone also mentioned that the line-flushing is implemented at the writer level and could change under people's feet who expected println! to always flush (like me). Why not cater to the 90% use case and make these both more user-friendly with guaranteed flushing? For the 10% writing performance-sensitive formatting code, explicitness, and usage of low-level APIs is probably already mandatory.
Reacted by Kenny, Bart Massey and Rasmus Källqvist
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?" (reactions which, imo, drive people away), but Rust By Example should certainly have a topic discussing this.
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 input function which covers this exact purpose of asking questions and waiting for answers.
People writing interactive command-line apps need to understand what flushing means
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:
it doesn't make sense that a line read contains the name if the "Name: " prompt wasn't flushed and therefore displayed beforehand
when communicating with a server, assuming the output to the server is buffered, if you make a request but then don't flush the request and then you block waiting the answer, it is safe to assume that the server never received the full request and therefore an answer will never be sent, the block on read being therefore infinite
Another question would be why print! and println! exist in the first place while a read! or readline! macro don't. Furthermore, why is there a need for print! when write! can be used? If their purpose is to make things easier, then why not go the extra step and fulfil the expectation that, when data is read from the standard input, all the data must be flushed to standard output?
Reacted by Willem Verstraeten, Vlad Frolov, Lalit Shankar Chowdhury, Adam, Jake Swenson, Kirill Elagin, Mihir Gadgil, Joseph Zeng, Juhan Oskar Hennoste, Karim Vergnes and 2 more
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!
As a quick survey, standard output is line buffered in C, C++, Python, and Ruby. Go's Printf buffers output and writes it to an unbuffered stdout. Java doesn't document what it does, but System.out appears to autoflush.
Note that the C and python behaviour (at least on Linux) is a bit more nuanced: It is line buffered when stdout is a terminal, and 1kB block buffered otherwise.
For processing large text files (either in a pipeline or writing to a file), the "unbuffered when not a tty" can make a huge performance difference (e.g., two orders of magnitude).
Activity
sfackler commentedon Mar 29, 2015
As a quick survey, standard output is line buffered in C, C++, Python, and Ruby. Go's
Printfbuffers output and writes it to an unbuffered stdout. Java doesn't document what it does, butSystem.outappears to autoflush.richo commentedon Mar 29, 2015
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
print*!machinery you're sufficiently far from the OS that you probably just do want some output to appear in the terminal.tanadeau commentedon Mar 29, 2015
@richo The implementation of
std::io::Stdoutis definitely line-buffered. Seerust/src/libstd/io/stdio.rs
Line 213 in 9f9e251
richo commentedon Mar 29, 2015
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.
alexcrichton commentedon Mar 29, 2015
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
print!flushes the output buffer.One downside of flushing on
print!would be that any form of "maximal buffering" when redirected to a TTY would be lost. For example C performs much more buffering when stdout is redirected than when it is to a console. This means that simple benchmarks which print information will be much slower in Rust than in comparison with others (due to the frequent flushing).I would be fine beefing up the documentation in this regard, of course!
richo commentedon Mar 29, 2015
That's totally reasonable, and mostly what I expected. Do you have a
citation about the c buffering though? That wasn't be belief and I'd love
to read more.
Will update the docs if no one beats me to it.
On Saturday, March 28, 2015, Alex Crichton notifications@github.com wrote:
tanadeau commentedon Mar 29, 2015
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
std::unitbufto making auto-flushing simple in cases like prompts and progress bars. This at least makes it so that users don't need to callflush()explicitly after every call.tanadeau commentedon Mar 29, 2015
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
coutwhencinis read, the following works fine there but the equivalent doesn't for Rust:Also according to the C standard:
nagisa commentedon Mar 29, 2015
println!macro, on the other hand, does not specify anything about its flushing semantics either. Even thestd::io::Stdoutdoesn’t and totally should.I generally really dislike implicit flushing and prefer to flush explicitly. On the other hand, there’s
write{,ln}!, which does not and can’t assume anything about buffering, so I’m ambivalent about this issue.alexcrichton commentedon Mar 30, 2015
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
flush(), but on the other hand you have worries about deadlocking, and/or surprising behavior happening behind the scenes. On the other hand you have to write a few moreflushcalls, but you know precisely what is happening and can avoid situations like deadlocking fairly easily.For example, what should this code do?
If
print!were to auto-flush, then it would deadlock the current process because the stdin handle was already locked. The alternative here is adding one call totry!(locked.flush())right above the call toread_line.nagisa commentedon Mar 30, 2015
I think you misunderstood what the issue is about: it is only proposed to flush std_out_ after
print!writes to the std_out_. i.e. changeto
Since
print!already takes a lock to write, this change will not introduce any more new cases where it deadlocks. For example snippet below deadlocks currently and will deadlock in all the same cases if we made it to auto-flush.I’m starting to believe that stabilising
Std{in,out,err}::lockwas a wrong and hasty move.alexcrichton commentedon Mar 30, 2015
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.
richo commentedon Mar 30, 2015
I think the crux of this is basically "What is the intent of print!". My
intuition is that it's not intended to be in the critical section, and is
instead meant to be a helper for "make this string appear on stdout", I
could really take or leave whether or not it flushes. That said,
considering that it already traverses all of the formatting machinery
anyway, if it can't deadlock my intuition is that the flush is just one
extra syscall to make this do something more user friendly/intuitive.
While I don't believe it's actually on the table, I would be a stoic -1 to
any suggestion of making all stdout writes autoflush.
On Mon, Mar 30, 2015 at 1:50 PM, Alex Crichton notifications@github.com
wrote:
tanadeau commentedon Mar 30, 2015
To address the performance considerations, could the
print!macro only flush stdout if stdout is attached to a TTY?65 remaining items
Lucretiel commentedon Dec 18, 2018
I'd be okay with a macro that guarantees a flush, but I'd be concerned about naming it
printf, since that's such a ubiquitous identifier in many other languages for "formatted print"anyputer commentedon Jan 31, 2019
How about
flprint!,flprintln!macros? Doingprintflln!orprintlnfl!would look confusing. Is it a problem if it starts withflcause that might makes it sound like the flushing happens first?dancojocaru2000 commentedon Mar 19, 2020
The main problem about
print!not flushing is when combining it withread!from thetext_iocreate.Considering this snippet of code:
The expected behaviour is this:
What actually happens is this:
C++ buffers
std::cout, however it ties it tostd::cinso thatstd::coutis flushed beforestd::cinreads any data, which solves this problem. This is not possible in this case for obvious reasons, so an alternative (perhaps aflprint!macro as suggested above?) should be found.frol commentedon Mar 19, 2020
@dancojocaru2000
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
text_iocrate.dancojocaru2000 commentedon Mar 19, 2020
print!is just a macro for dumping stuff intostdout, and it has no connection to anything else (I would assume). A flush+read fn/macro would unnecessarily do two things in one package, restricting flushing only to the case where a read is required.Having the option to print and flush in one macro, unbounded from needing to also read, seems like a good addition to the language.
samclaus commentedon Apr 28, 2020
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
print!instead ofprintln!(so the guess would be on the same line, after a colon). Curiosity lead me here.If no changes are going to be made for
print!, the book should definitely use it and mention the flushing semantics.With that said, I personally think
println!andprint!are used for simple logging or when getting input from the user 90% of the time. Someone also mentioned that the line-flushing is implemented at the writer level and could change under people's feet who expectedprintln!to always flush (like me). Why not cater to the 90% use case and make these both more user-friendly with guaranteed flushing? For the 10% writing performance-sensitive formatting code, explicitness, and usage of low-level APIs is probably already mandatory.dancojocaru2000 commentedon Apr 28, 2020
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?" (
reactions which, imo, drive people away), but Rust By Example should certainly have a topic discussing this.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
inputfunction which covers this exact purpose of asking questions and waiting for answers.dancojocaru2000 commentedon Jan 3, 2021
@dtolnay
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
print!andprintln!exist in the first place while aread!orreadline!macro don't. Furthermore, why is there a need forprint!whenwrite!can be used? If their purpose is to make things easier, then why not go the extra step and fulfil the expectation that, when data is read from the standard input, all the data must be flushed to standard output?cdecompilador commentedon Jul 12, 2021
This is my personal suggestion to the problem:
being
shouldflushjust an optional token, as far as I know this is possible.Maybe other options might be passing a boolean, or
flush, orshouldflush = truepawkw commentedon Jul 12, 2021
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!
LollipopFt commentedon Feb 24, 2022
what is the difference between
print!andwrite!? aren't they basically the same?Lucretiel commentedon Feb 24, 2022
They are basically the same;
write!allows you to write to any stream, whereasprint!specifically writes to stdout.bazzilic commentedon Sep 26, 2023
Just to add my 5 cents, I think
print!should not flush because line-buffered output is the expected behavior, butrcls commentedon Apr 18, 2025
Note that the C and python behaviour (at least on Linux) is a bit more nuanced: It is line buffered when stdout is a terminal, and 1kB block buffered otherwise.
For processing large text files (either in a pipeline or writing to a file), the "unbuffered when not a tty" can make a huge performance difference (e.g., two orders of magnitude).