Skip to content

Add file-open-with RFC #2615

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

Closed
wants to merge 1 commit into from
Closed

Add file-open-with RFC #2615

wants to merge 1 commit into from

Conversation

Timmmm
Copy link

@Timmmm Timmmm commented Dec 16, 2018

Rendered

This RFC proposes making File::open() consistent by deprecating OpenOptions::new().read(true).write(true).open("existing_file") and adding File::open_with("existing_file", OpenOptions::new().read().write()) instead.

Suggestion based on rust-lang/rust#55762.

@Centril Centril added the T-libs-api Relevant to the library API team, which will review and decide on the RFC. label Dec 16, 2018

let mut file = File::open_with("foo.txt", OpenOptions::new().read().write());

This matches the normal way of doing "call a method with some options" in Rust, for example `TcpStream::connect(addr)` and `TcpStream::connect_timeout(addr, timeout)`.
Copy link
Contributor

Choose a reason for hiding this comment

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

The current pattern, however, matches the well-known and frequently used builder pattern. Since you have to use OpenOptions anyways, I don't really see how this improves on just calling .open on that.

Copy link
Author

Choose a reason for hiding this comment

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

The improvement is discoverability and consistency. There's already File::open() and File::create() which leads users to believe that to open files you use a method on File.

If OpenOptions had been named FileOpenBuilder or something then I agree it would have been a bit clearer but given that it isn't, and that the most obvious methods to open a file are on File it seems silly that some random subset of file open methods are on OpenOptions.

This may be one of those things that feels obvious once you have learnt it, but as a Rust beginner, trust me this was weird and confusing. (And see the Stackoverflow questions for further evidence.)

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps then the docs on File::{open, create} should be improved to mention that you need to use OpenOptions to configure permissions

Copy link
Author

Choose a reason for hiding this comment

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

That would certainly be a good thing to do, however it would be better if the API were intuitive in the first place. Nobody likes reading documentation.

Copy link

Choose a reason for hiding this comment

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

The discoverability of OpenOptions definitely has room for improvement. I recall being a little confused when I first needed it and saw nothing obvious associated with File.

As an alternative, we could add an open_options constructor to make it easier to find while staying true to the builder pattern.

From your example:

let mut file = OpenOptions::new()
    .read(true)
    .write(true)
    .open("foo.txt");

Would also be available via:

let mut file = File::open_options()
    .read(true)
    .write(true)
    .open("foo.txt");

And implemented:

impl File {
    pub fn open_options() -> OpenOptions {
        OptionOptions::new()
    }
}

Copy link
Contributor

Choose a reason for hiding this comment

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

For the specific use case of opening a file, I don't think the builder pattern makes much intuitive sense. After all, you're not building a file. You're building an OpenOptions object. Or perhaps you could say you're building a file descriptor. But it seems weird to say that the file itself has been "built" before we write any content into it. Maybe it's possible to design a useful FileBuilder API where .build() actually puts content in the file, but that'd be a layer above what std is trying to provide.

I think it's clear that File::open(name, options) is a much more intuitive API. To me the only question is whether adding it and deprecating the already stable alternative is a net win for the language and its ecosystem, which is where I'll have to defer to others who know the Rust ecosystem much better.


```
impl File {
pub fn open_with(filename: &str, options: &OpenOptions) -> File {
Copy link
Member

Choose a reason for hiding this comment

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

This will need to take the same AsRef<Path> type parameter as File::open.
https://doc.rust-lang.org/std/fs/struct.File.html#method.open

@sfackler
Copy link
Member

I like @aloucks's alternative better - it solves the discoverability issue, and improves on both open_with and the status quo by not requiring you to import OpenOptions at all.

@sfackler
Copy link
Member

RFCs aren't normally required for small API additions like this, BTW. You can just make a PR.

@Centril Centril added the A-file Proposals relating to file systems. label Dec 17, 2018
@Timmmm
Copy link
Author

Timmmm commented Dec 17, 2018

Ah ok. I think @aloucks's suggestion is an improvement too. I'll make a PR for it since it seems to have the most support.

@aldanor
Copy link

aldanor commented Dec 19, 2018

As an alternative, we could add an open_options constructor to make it easier to find while staying true to the builder pattern.

// bikeshedding

Another option would be to call the constructor method with_options() (instead of open_options()), like:

impl File {
    pub fn with_options() -> OpenOptions {
        Default::default()
    }
}

...

File::with_options().write(true).open("foo.txt");

The tiny difference being -- that it reads much more naturally like a proper English sentence. As in, "With options this, this, this, and that, open foo.txt".

@Timmmm
Copy link
Author

Timmmm commented Oct 15, 2019

Closing in favour of #65429.

@Timmmm Timmmm closed this Oct 15, 2019
bors added a commit to rust-lang/rust that referenced this pull request Nov 2, 2019
Add File::with_options

This provides a more fluent API to create files with options, and also avoids the need to import OpenOptions.

This implements @aldanor's [suggestion](rust-lang/rfcs#2615 (comment)) which was popular.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-file Proposals relating to file systems. 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.

8 participants