Skip to content

Tracking issue for File::with_options stabilisation #65439

Closed

Description

@Timmmm

Implemented in #65429, behind feature flag with_options.

Activity

  1. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    T-libs-api[DEPRECATED; DO NOT USE]
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Oct 15, 2019
  2. Kinrany commented on Feb 23, 2020

    @Kinrany
    Contributor

    Just a thought about an alternative API:

    let f = File::with_options("file.txt", |o| o.read(true).create(true));
  3. LPeter1997 commented on Apr 12, 2020

    @LPeter1997

    From the name I'd associate it with a function that takes an OpenOptions parameter, just like Vec::with_capacity takes a capacity. Basically not a builder type. For consistency's sake, why not either add a File::with_options(options: &OpenOptions) or rename it to something like File::builder()?

  4. Timmmm commented on Apr 14, 2020

    @Timmmm
    ContributorAuthor

    LPeter1997, that was my original suggestion but people overwhelmingly preferred this API.

  5. TheRadioGuy commented on Jul 1, 2020

    @TheRadioGuy

    I agree with @LPeter1997. I think it'd be better to rename it to something like File::options()

  6. Timmmm commented on Jul 1, 2020

    @Timmmm
    ContributorAuthor

    I guess File::options() makes more sense when you just look at that API but File::with_options() makes more sense in typical usage.

    let options = File::options(); // Ok
    let options = File::with_options();  // Weird
    
    let file = File::with_options().read(true).create(true).open("foo.txt"); // Ok
    let file = File::options().read(true).create(true).open("foo.txt"); // Bit weirder. Maybe it is better actually?
    

    Not that this is a democracy, but let's have a poll: upvote one or more of the following options...

  7. Timmmm commented on Jul 1, 2020

    @Timmmm
    ContributorAuthor
    pub fn with_options() -> OpenOptions {
      OpenOptions::new()
    }
    
    let options = File::with_options();
    let file = File::with_options().read(true).create(true).open("foo.txt");
    
  8. Timmmm commented on Jul 1, 2020

    @Timmmm
    ContributorAuthor
    pub fn options() -> OpenOptions {
      OpenOptions::new()
    }
    
    let options = File::options();
    let file = File::options().read(true).create(true).open("foo.txt");
    
  9. Timmmm commented on Jul 1, 2020

    @Timmmm
    ContributorAuthor
    pub fn builder() -> OpenOptions {
      OpenOptions::new()
    }
    
    let options = File::builder();
    let file = File::builder().read(true).create(true).open("foo.txt");
    
  10. Kinrany commented on Jul 2, 2020

    @Kinrany
    Contributor

    From the API discovery point of view it's not great to have the only actual verb be the last in chain.

    From the point of view of making code nicer to read, it's not great that open is not in any way syntactically distinguished from the rest of the methods. The reader has to inspect the types to find out that all but the last one return the same OpenOptions type. (It doesn't help that other methods are verbs too, even though they refer to fields and would be nouns in most other builders.)

  11. added
    I-libs-radarLibs issues that are tracked on the team's radar.
    A-ioArea: `std::io` (note: `std::fs`, `std::net`, `std::path` are A-filesystem, A-net, A-path)
    on Jul 29, 2020
  12. tesuji commented on Sep 15, 2020

    @tesuji
  13. 22 remaining items

  14. workingjubilee commented on Jun 4, 2021

    @workingjubilee
    Member

    I think the argument about whether something sounds like a nullary function or not is valid, and is reasonable grounds to exclude File::with_options() from the running. But we already have OpenOptions as a very... interesting type name. So to me, I agree that nullary File::open_options() is quirky, but I also think it's "natural" to Rust, simultaneously, because of the existing legacy of OpenOptions. I believe it's reasonable to lean into the quirkiness. But of course, File::options() is also good to me.

    So, I feel it is copacetic either way, and

    open_options seems reasonable but I think all of the options (heh) are reasonable. Doesn't seem like it's enough better to bother changing the PR again.

    I am happy to repaint the bikeshed if people can agree on a color!

  15. joshtriplett commented on Jun 4, 2021

    @joshtriplett
    Member
  16. m-ou-se commented on Jun 4, 2021

    @m-ou-se
    Member

    agree on a color

    Pink!

    image

  17. Timmmm commented on Jun 5, 2021

    @Timmmm
    ContributorAuthor

    Where did I say this?

    Sorry, "you" was referring to m-ou-se.

  18. simias commented on Jun 10, 2021

    @simias

    I'd like to restate that IMO options() has the advantage of being a generic name that could be reused for other APIs which in turn could help discoverability. It could join new(), iter() and other well known method whose semantic you can guess without even having to look at the docs. You could have an option() method for an OpenGL context object, a database handle object, a cryptographic algorithm object etc...

    open_options() is also fine, but that would make it semantically a little more "narrow" IMO. I suppose that for a DB handle the metaphor also works, but you don't typically "open" a SHA1 context for instance, you create it.

    But I agree that this is a pure bikeshed at this point. If open_options is favoured, I'm absolutely fine with it.

  19. workingjubilee commented on Jul 5, 2021

    @workingjubilee
    Member

    Recap

    • m-ou-se suggests File::open_options() as an alternative, because it sorts directly next to File::open(Path) in the method overview, and proposes other shorthands like File::open_rw(), File::open_append(), or File::create_new().
      • Question: Is the function sorting algorithm for rustdoc stable or likely to change?
      • Question: Where does create_new() come in here? How exactly would it differ from create(Path) in usage?
    • Josh suggests OpenOptions is meaningfully distinct from File::open_options() because it's a type (a "noun") not a function (a "verb"), and thus dissociated from File.
    • Josh suggests fn open_options(arg) -> OpenOptions is what he would expect, on the basis of the "verb" being included and implying something similar to with_.
      • Question: If this is an expected pattern, maybe other examples of this already exist? What do programmers currently write, and thus, expect?
    • Jubilee (hi!) suggests the name is quirky regardless.
      • Question: How did we arrive at the original name anyways?
    • Josh suggests that fn open(Path) and fn open_options() are unnecessarily ambiguous next to each other.
      • Question: Isn't that the point, actually? That both are valid ways to start the same code string?
    • simias believes that fn options() will carry more weight over time (alongside fn option()) and become a common library pattern.
      • Question: If it seems like a commonly reusable pattern, maybe it has already arisen? What do programmers currently write, and thus, expect?

    Other Ideas

    If the problem is imports, why not just use an std::fs::prelude::* a la std::io::prelude::*?

    Reflections

    Rereading this reveals what now feels like a misstep in the early drafts of the File API, and I would like to offer these remarks to both m-ou-se's and Josh's comments regarding the relationship (or not) of OpenOptions, fn open_options, and fn open:

    I don't think it's a problem that fn open_options is nullary whereas fn open is unary, or that one is a constructor for a Result<File> and the other is a constructor for an OpenOptions that will eventually yield a Result<File>.

    I think the problem is that they are actually logically unrelated, or perhaps I should say that OpenOptions is the distant ancestor of File::open(Path), not the immediate parent. OpenOptions is far more ambiguous than what you can get from File::open(Path) because it can imply creating a file, appending to an existing file, reviewing and editing the contents of an existing file, or opening a file in read-only mode. File::open(Path) only supports the last. Thus File::open_options() would only bear a passing resemblance in use to File::open(Path), which would actually be something more like File::read(Path) if I had my druthers.

    This difference itself would not be a huge issue, honestly, but we have a relatively strong norm of highly "patterned" names in other std APIs, and people would expect two names which use the same initial word to have similar meaning, when one is far different. But I don't believe that is a definitive argument against using fn open_options() per se, merely that it is an issue. I would probably want to research answers to some of the other questions more.

  20. workingjubilee commented on Jul 5, 2021

    @workingjubilee
    Member

    A quick skim of grep.app for open_options reveals that the dominant use of it is "a variable or struct field that is OpenOptions". In one or two cases it is in fact used as "open with this OpenOptions".

    Searching for the regexp /fn open_.*\(/ yields quite a lot of examples of "open_something that takes an argument", it's true.

    /fn options?(<.*>)?\(/ shows that fn option and fn options are both about equally often a "getter" and a nullary constructor, and sometimes it also takes an argument other than self.

    So there's some data: clear as mud! 😃

  21. jplatte commented on Sep 22, 2021

    @jplatte
    Contributor

    Another possibility: First introduce additional File constructors such as File::(open_)?append, then re-evaluate how much the additional OpenOptions constructor is.

  22. yaahc commented on Oct 14, 2021

    @yaahc
    Member

    This has been stalled for a while and so I'm nominating it for discussion in our next meeting to help it get unblocked.

  23. yaahc commented on Oct 20, 2021

    @yaahc
    Member

    The PR stabilizing this feature, #85766, has entered its final comment period with disposition merge.

  24. added a commit that references this issue on Nov 9, 2021
  25. added a commit that references this issue on Nov 16, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ioArea: `std::io` (note: `std::fs`, `std::net`, `std::path` are A-filesystem, A-net, A-path)B-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCI-libs-radarLibs issues that are tracked on the team's radar.T-libs-api[DEPRECATED; DO NOT USE]

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions