PathBuf vs &str; Philosophy of usage

Say, I want to pose some abstract questions, if that won't bother anyone:

File open wants a PathBuf object, but create_dir_all wants a string slice. Is this just unintended or uncoordinated design, or is there a philosophical intent for when we should use PathBuf, and when we should use strings. I am, by preference, just a Linux programmer, so I don't tend to care whether something works on other OS environments. Please advise on any level or sub-topic regarding these matters you feel compelled to or that is helpful.

???

pub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()>
4 Likes

Sorry. I don't need help with the commands. I want insight into the implementation of the functions. Is there a time when we should use &str, and others when we should use &str? It seems like create_dir_all is just as good a place for PathBuf as any other command. This may not be knowledge that is generally available, but it may also be related to coding philosophy on usage.

Both want something that can be reference-converted to a &Path. That includes PathBuf, &Path, &str, String, OsString, ...

My advice when writing your own function that need a &Path and not ownership are

  • Just take a &Path
    fn f(path: &Path)
    
  • Be generic but take a reference to something ?Sized and use an inner function
    fn f<P: AsRef<Path> + ?Sized>(path: &P) {
        fn realf(path: &Path) {}
        realf(path.as_ref())
    }
    

The only thing the former loses is some calling ergonomics (at the cost of monomorphization) and the only thing the latter loses over the more common version is how pretty the declaration looks.[1]

The inner function defrays monomorphization cost (with this signature, or the common one).


  1. an incredibly horrible metric for API design but actually why it was chosen for std (!), to the detriment of the ecosystem ↩ī¸Ž

6 Likes

Rust API Guidelines: Functions minimize assumptions about parameters by using generics (C-GENERIC)

1 Like

Your original assumption is wrong. Both std::fs::create_dir_all and std::fs::File::open take a generic argument that looks like P: AsRef<Path>. That is what @vague tried to tell you. As @quinedot pointed out, that can be any of PathBuf, &Path, &str, String, OsString and more.

pub fn open<P: AsRef<Path>>(path: P) -> Result<File>;

pub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()>;
4 Likes

Thank you. But, I did not get that from the docs I originally read. I wonder if I've been pulling up the wrong drafts of docs somehow.

Yes, you know I wonder if I'm depending too much on google, and I need to have a better starting point for looking up syntax.

The inner function part on this is making me feel dumb. I'm sorry. It cannot be using function overloading, but I am probably too tired. Will look again in the morning. Thank you for all this.

I have never seen the single parameter Result like that. I've only seen it with two items: Result<T,E>.

Click the type on the documentation page @vague linked; you'll find it's a type alias with a particular error variant.

It's a common optimized-for-writing patten.

3 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.