Semantics of an empty `PathBuf`

Today I found that the equal sign (==) will treat paths with dots (.) appended to them as equal, like this:

// `p` is a `PathBuf`
if p.join(".") == p.join(".").join(".") {
    println!("same");
}

// Above code prints "same" on a new line

So I wonder what is the semantic of an empty PathBuf? Because when I play around with the equal sign(==), I found this behaviour:

let s: PathBuf = "".into();
assert_eq!(s, s.join("."));  // Panics
assert_eq!(s.join("."), s.join(".").join("."));  // Ok

I expected an empty PathBuf to have the same semantics as a dot (.), because if I want to join an empty path a with another path component b, the result is expected to be relative to current working directory. But the above code implies that an empty PathBuf does not have a meaning?

My question here is: why doesn't empty PathBufs have the same semantics as .? Please point out if I'm missing anything from the documentations. Thanks!

PathBuf::PartialEq compares components(); how exactly the components are normalized is documented here.

2 Likes

Hi @H2CO3, thank you for the link to the documentation!

Now I do understand how they are compared internally (by comparing components and the components() method normalizes away the dots), is there any explanation to why doesn't empty PathBufs have same semantics as a single dot (".")? Since:

  1. when appending a new component "comp" to an empty path, the resulting path is interpreted as rooted from current working directory, which has the same semantics as appending "comp" to a ".";
  2. when appending an empty path to a non-empty path "p", the resulting path still has only "p" in its components, which also has the same semantics as appending "." to "p".

Or is using empty PathBufs undefined behavior in Rust? If so, given the two points above, why doesn't Rust define it?

Thanks in advance!

I'm not entirely sure about the deeper reason for this design decision (if there was one at all). Judging from the trivial equality implementation, I'm inclined to think that it was done this way because they wanted something simple yet reasonable.

No, it can't be. It's not possible to cause UB in Rust unless some unsafe is involved somewhere, and APIs are supposed to be designed in a way that always upholds this contract.

1 Like

At least the bash shell and the coreutils commands don't treat them identically. I tested it on both linux and macos, cp '' acts like cp . but ls '' prints No such file or directory error.

1 Like

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.