6 ms·
> The next noisy element is the <P: AsRef<Path>> constraint. It is needed because Rust loves exposing physical layout of bytes in memory as an interface, specif
by jiwangcdi 2y ago
> The next noisy element is the <P: AsRef<Path>> constraint. It is needed because Rust loves exposing physical layout of bytes in memory as an interface, specifically for cases where that brings performance. In particular, the meaning of Path is not that it is some abstract representation of a file path, but that it is just literally a bunch of contiguous bytes in memory.
I can't understand this. Isn't this for polymorphism like what we do this:
```rust
fn some_function(a: impl ToString) -> String {
a.to_string();
}
```
What to do with memory layout? Thanks for any explanation.
- K0nserv 2y agoRust needs to know the exact size, layout, and alignment of every argument passed to a function to determine how it gets passed(register(s) or spilled to stack) and used. For example PathBuf and String can both be turned into a reference to a Path, and while they have the same size their layout and implementation of `as_ref` differ. As for `impl`, fn foo(a: impl ToString) is syntactic sugar for fn foo<S: ToString>(a: S) The reason the standard library doesn't use this is because the code predates the introduction of `impl` in argument position. The reason the function takes `AsRef<Path>` instead of `&Path` is callsite ergonomics. If it took `&Path` all callsites need to be turned into `read(path.as_ref())` or equivalent. With `AsRef<Path>` it transparently works with any type that can be turned into a `&Path` including `&Path` itself.
- jiwangcdi 2y agoThen if Path is not about abstraction, why not use a raw byte slice like &[u8]
- K0nserv 2y agoThat's orthogonal. If the type was `&[u8]` instead of `Path` the type signature would be: pub fn read<P: AsRef<[u8]>>(path: P) -> Result<Vec<u8>> The reasons for it to be generic and us `AsRef` remain. The reason for Path over &[u8] is, AFAIK, because not all byte slices are valid paths on all OSs, but also because a dedicated type lets the standard library add methods such as `Path::join`
- jiwangcdi 2y agoSo abstraction is still a point, but Rust cares about memory layout as well.
- K0nserv 2y agoSort of, this API enables static dispatch, but it could also have been written as pub fn read<P: AsRef<Path>>(path: &dyn P) -> Result<Vec<u8>> In which case the size of `path` is always the same(two words[0]) and the same machine code could be used regardless of how the function is called. Rust still cares about the memory layout but because `&dyn AsRef<Path>` has the same layout for all implementations of `AsRef<Path>` there's no need for monomorphization[1]. 0: https://doc.rust-lang.org/1.80.1/reference/types/trait-object.html https://doc.rust-lang.org/1.80.1/reference/types/trait-objec... 1: https://rustc-dev-guide.rust-lang.org/backend/monomorph.html#monomorphization https://rustc-dev-guide.rust-lang.org/backend/monomorph.html...