Hacker Newsnew | past | comments | ask | show | jobs | submit | jiwangcdi's commentslogin

> 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.


Rust 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.


Then if Path is not about abstraction, why not use a raw byte slice like &[u8]


That'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`


So abstraction is still a point, but Rust cares about memory layout as well.


Sort 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-objec...

1: https://rustc-dev-guide.rust-lang.org/backend/monomorph.html...


Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: