Contradicting information

How is it possible that method to_string exists, as the error msg says, but trait bounds were not satisfied, which basically means "some" interface is not implemented for that type.
So which one is it, does the method exists and if so I should be able to use it or the interface is not implemented and thus the method doesn't exist and I cannot use it!!!
Which one is it????
Have to be honest, some of the rust terminology, like bounds not being satisfied is so alien to most of the not even programmers, but people in general that I'm really struggling why the well known terminology, ie "interface" wasn't used in the first place. Just to be different? Silly argument.

error[E0599]: the method to_string exists for struct PathBuf, but its trait bounds were not satisfied
--> src/fm_table.rs:359:72
|
359 | *rc_current_path.borrow_mut() = path_t.clone().to_string();
| ^^^^^^^^^
|
::: .rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/std/src/path.rs:1156:1
|
1156 | pub struct PathBuf {
| ------------------
| |
| doesn't satisfy PathBuf: ToString
| doesn't satisfy PathBuf: std::fmt::Display

PathBuf doesn't have a .to_string() method as a path doesn't need to be UTF-8 while a String must be. Are you sure you want to turn it into a String? If this is only for showing the path to the user you can use .display() which does a lossy conversion to UTF-8.

Honestly, sometimes this particular error message is just stupid. There is no to_string method on PathBuf.

1 Like

How this what you've said^^^ ties with what compiler says:

"the method to_string exists for struct PathBuf"

Thanks, brings back some normality to my world :slight_smile:

It is a bit misleading. The .to_string() method exists on the ToString trait. There is a blanked implementation of ToString, but only for types implementing Display. I believe rustc thinks it needs to use this blanket implementation and then complains that the Display bound isn't satisfied for PathBuf.

1 Like

It is actually just misleading. Full stop.

The reason for the error message is that the standard library has the following snippet (simplified a bit):

impl<T: fmt::Display> ToString for T {
    fn to_string(&self) -> String {
        ...
    }
}

which is short-hand for

impl<T> ToString for T
where
    T: fmt::Display
{
    fn to_string(&self) -> String {
        ...
    }
}

The <T> part makes this generic, making it apply to all types. The parts after the where is then the list of bounds (requirements) for the impl block, and only types that satisfy all of the trait bounds are actually affected. This kind of impl block is called a blanket impl.

The error appears because PathBuf is part of "all types" — it just doesn't satisfy the trait bound that PathBuf must implement Display. You're going to get this error on any type that does not implement Display.

The error message is trying to be helpful by explaining why the blanket impl does not apply here.

8 Likes

Perhaps if the error msg actually mentioned the word blanket, it would help. A bit.

I wonder if that error message could be improved to something like "the method to_string doesn't exist for struct PathBuf", then in a note/help section explain "the method to_string would exist for struct PathBuf, but the following trait bounds were not satisfied: doesn't satisfy PathBuf: ToString doesn't satisfy PathBuf: std::fmt::Display".

4 Likes

Could we also get rid of that fugly "trait bounds" and call it for what it is: an interface?
The interface X is not implemented for type T sounds normal.
Trait bounds X are not satisfied for type T sounds at best confusing.

I actually every time read about trait bounds not being satisfied, translate it in my head to iface not being implemented.

Well, there's nothing in Rust called an interface, but you could certainly write "The trait X is not implemented for the type T".

However you should keep in mind that trait bounds can be more complicated. For example, they might say this:

where
    u32: From<T>,

That would be a requirement that the u32 type implements the From<T> trait, where T is your generic type.

1 Like

But trait is nothing more that interface. It is just called differently.

Again, interface From < T > is not implemented for u32

Wouldn't it be confusing to sometimes call the same thing a trait, and sometimes call it an interface?

2 Likes

Yes it would. That's my main peeve with interfaces being called traits in rust. Is there any other language that doesn't call interface interface but some forced, just to be different and awkward word?

Rust traits are not entirely the same as, say, Java interfaces. The only other language I know of which has an exact equivalent to Rust traits is Haskell, which calls them type classes.

There's Scala, but their traits are actually just interfaces.

1 Like

They serve exactly the same purpose

Well, they are in some ways more powerful. See e.g. the Default trait. You can not implement anything like that in Java. See also the Send/Sync traits, which don't even have any methods.

They serve exactly the same purpose. Namely, describe, what you can and can't do with a type/object.