-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
io error handling design #770
Conversation
-1 this kinda disagrees with Rust's RAII in my opinion. |
I like the ideas in this, but am not sure at all if this should be applied to all kinds of Writers. I do think it is absolutely necessary for some Writers to force explicit errorhandling on close() |
Previous discussion: https://github.com/rust-lang/rfcs/pull/576/files#r23805711 |
@sinistersnare I think the link above explains why RAII doesn't work for some kinds of Writers. |
@sinistersnare RAII is a great way to release resources and that's what we're doing. An unflushed buffer in BufferWriter is being released. But what we're not doing is attempting to create new resources, e.g. on the filesystem, with no way to relay errors because we don't want to panic in a destructor. |
-1 The current way works well in practice which means that this RFC is a serious step backwards for most users. |
I feel like the sort of random panics that are trying to be prevented in this RFC are still in Rust in a few ways. For example, Basically, I do not think that the correctness benefit is greater than the ergonomic loss. However, if there is a resounding yes to this proposal, I am no language designer (I wish I was, but alas), so I wont be too upset it if was accepted. Thanks for the reading, I am currently procrastinating homework, but I will try to read that later :) |
I agree with you, but IMO it's less problematic with println, because if you want to explicitly handle errors, stdout.write is not too low-level. I suppose ideally Rust would have an API with explicit error checks, and one for the common usecase which panics on edgecases. |
There was a discussion about the same issue but for C++: the ideal semantics IMO, would be for the guard to flush and close the underlying stream iff it exits the scope normally, rather than as the result of a panic and stack unwinding. Errors from close result in a panic (to avoid this, close must be called explicitly and the errors handled) The problem is that it's impossible to implement this correctly using only a library method such as "is thread panicking" to be called from the destructor to determine whether to close() or not, because even during a panic, a guard within a destructor can exit scope normally. Possible implementation: add a "Closable" trait. The compiler will automatically insert calls to "close()" when a stack object implementing that trait leaves scope normally (ie. not as part of unwinding). For Closable objects constructed on the heap, it is up to the owner to call "close" explicitly. For example, Box<T: Closable> should itself implement Closable and forward on the calls as expected. |
Thanks @Diggsey for that comment about a guard in a destructor. I added a note "Note that this can give a false negative" in the RFC, but I am doing the reverse logic as what you are suggesting. And +1 to your comment. I'm trying to decide if it's backwards compatible with my proposal. We could say implicit drop has undefined behavior if you didn't call close(), and leave it at that until Closeable happens, and then it changes to defined behavior - nothing happens unless it left scope normally, in which case it is closed, but then that could in theory cause panics in code that didn't before. |
@Diggsey the way to stop Closeable would be to explicit drop(myfile), right? In case you wanted to be future proof. e.g. in pseudocode: do_something_with(&my_file) I'm assuming there is potentially a use case somewhere where you don't want to flush and close the buffered file in some circumstance. |
@kjpgit Yeah, anything which consumes the Closable would prevent the compiler from emitting calls to close or drop as usual. The drop method itself shouldn't call close either, so that gives you a way to avoid it. I think adding Closeable later can be made backwards compatible, as long as a few conditions hold:
|
@Diggsey I'm still confused how the automagic scoped_close() method is prevented. drop is literally an empty function, and we want to move file objects around to new scopes. So both the close() method itself needs a way to take ownership, close resources, and drop without having the scope_close() called again. Same with the example code I did earlier. There seems to be a more magical drop() needed. |
Sorry I phrased that badly, when I said "drop" shouldn't call close, I meant it should be defined to not call close, not that it will already behave that way under the current implementation. |
@Diggsey I think the Closeable will unfortunately cause panics with people who are trying not to write panicing code. E.g. try!(my_file.close()); Is obviously designed not to panic, but if Closeable is the default, if my_file fails and try! tries to return an error, and then my_file2 also fails autoclose, it will cause a panic where there shouldn't have been one. |
@mahkoh "The reason why rust "somewhat" works today is because Rust's stdout |
@kjpgit That's a difficult case - I'm starting to think that explicit close might be the best we can do. In combination with a lint it shouldn't be too bad. |
@kjpgit: I consider panic quite useless and would not mind having it replaced by abort. Either way, you wouldn't use println! and friends outside of toy programs. |
I think the use case to have |
To clarify the comment above: I support the need for |
Making the types that need explicit |
When we discussed this (fairly extensively) during IO reform, one of the basic questions was: what errors can you receive when trying to close a file that would not also arise by flushing it? That is, in what circumstances is calling cc @sfackler |
It's not a file... but a block mode cipher that's had an incomplete block of data written to it can't |
@gkoz That's an interesting example, but it's not clear why |
@aturon Generally, it could work but when doing foreign library bindings (e.g. rust-openssl) it's not always possible. Or rather I'd say openssl actively refuses to play by Rust's rules ;) (We could catch the case of unaligned end of data in block modes relatively easily, tracking padding would require some effort and overhead, the authentication case? well...) Isn't it also a bit odd for |
To rephrase the last point, is it appropriate for |
@aturon I'm confused. Are you inquiring about something besides what the close(2) NOTES section on linux talks about? |
The implementations of |
This RFC is now entering its week-long final comment period. My personal feelings on this RFC is that while it may certainly be desirable to have a |
I agree with @alexcrichton; while there is a hypothetical need for this functionality, I think we have much bigger fish to fry with respect to IO, and I would prefer to wait on this until there is a more clear need for the functionality. It's worth noting that, especially with the forthcoming |
I'm not sure what bigger fish to fry there are than making sure data isn't On Thu, Jul 16, 2015 at 11:03 AM, Aaron Turon notifications@github.com
|
I, too, think it a pity that one needs more than the standard library to use the basic file functionality on POSIX systems with a degree of reliability that the developers are accustomed to (no hard write-through guarantee, but a number of easy-to-detect errors not going unreported either). Hiding a potentially blocking operation in the destructor without an explicit way to invoke it or drain the output buffer (files only have |
I think this is a bit hyperbolic to say, so it may not be 100% faithful to this RFC. We will always have primitives close themselves on drop, so receiving an error from the
I'm not sure this is a line of reasoning we can follow too far though as it's unclear how many possible designs there are in this space. As I mentioned above, we're always going to call It seems like we will fundamentally always close I/O objects on drop, and then we will also very likely provide the ability to manually close an object to see if any errors arise. It will always be an opt-in to seeing the error on |
The problem is that right now there isn't an obvious way to write to a file and check whether an error has occured. That's pretty fundamental if you ask me. To hyperbolize this point a bit, not checking the return value of I fail to understand how you can brush this off as a minor issue. :( |
As far as I understand On Fri, Jul 24, 2015 at 02:59:20PM -0700, tbu- wrote:
|
@untitaker |
@untitaker @tbu- As there seems to be confusion regarding Rust's current behavior:
|
The consensus of the libs team this week was to close this RFC. While it's something we may want to add to the standard library in the future, with the addition of Thanks again for the RFC @kjpgit! |
thanks for reading!