(May be) misleading error message?


#1

Hello All,

I am doing my first steps in Rust and I bumped into an error message that I feel misleading:

src/x/mod.rs:22:33: 22:34 error: the trait core::fmt::Debug is not implemented for the type T [E0277]
src/x/mod.rs:22 println!(“trait: {:?}”, i);

I didn’t want to file an issue/bug because I wanted to verify my understanding with you. May be I am completely wrong.

I documented my code and use-case here http://dbeck.github.io/My-First-Steps-In-Rust/.

My view about this message is that it should reflect the fact that the type T is potentially used for types that doesn’t implement the Debug protocol, rather then stating that it is not implemented, which in my case is just not true.

I am very much interested in your opinions. Please treat me as a rust beginner and sorry for the potentially silly question. What do you think?

Thank you very much, David


#2

Well, the key insight here is that T is not f32 or i32; it’s a distinct concept. I mean, sure, it has f32 and i32 substituted in its place, but so far as the compiler is concerned, T is its own thing within that code.

To put it another way: the only things the compiler is allowed to assume about T are the things you’ve specifically told it.

The message could probably be improved by checking for generic parameters and noting that you maybe need to constrain them. Rust has similar suggestions in a few places already.


#3

I see, thank you very much for the reply. Once I understood, I liked this way of treating generics, actually a lot more than it is in C++ templates.

Since this is my first few lines in Rust it took quite some time to understand what was wrong. I think it is more helpful for the beginners like me to improve the error message.

So I like how Rust works as much I understood, just the error message has raised the bar to jump in.


#4

I’m not sure I would call the error misleading. Is there a compiler out there that looks at the actually implemented instances of a generic to infer what traits (interfaces) it has?

Well there is JavaScript I guess, but that’s an interpreted language so the methods an object has isn’t know until it actually runs…

And if this generic is put into a crate (library) that would be impossible because it wouldn’t know until it tried linking with the external code.

I know in Java I can’t create a generic and call random functions on it, I have to tell Java what interface/class the generic implements or extends before I can call functions on it. But maybe that is a bad example because Java is a pretty old language now. Not sure about the some of the newer non interpreted languages…


#5

I found it misleading (may be because of my C++ background) because I read it like I need to implement something additional for T, rather then constraining the T in the generic trait. May be one more sentence clarifying this would be helpful for the poor C++ folks.

I started to realize that others, coming from non-C++ background understanding the message easier than I did.


#6

The rustc_on_unimplemented message for fmt::Debug is confusing:

note: `T` cannot be formatted using `:?`; if it is defined in your crate, add `#[derive(Debug)]` or manually implement it

Maybe we should not display the rustc_on_unimplemented message when the type is not implemented because of type parameters (e.g. replace the type parameters with variables and check whether the evaluation is ambig?).


#7

PR: https://github.com/rust-lang/rust/pull/32583


#8

Wow. You are fast. For my curiosity what would rustc print with this change?


#9
example.rs:19:33: 19:34 error: the trait `core::fmt::Debug` is not implemented for the type `T` [E0277]
example.rs:19         println!("trait: {:?}", i);
                                              ^
<std macros>:2:25: 2:56 note: in this expansion of format_args!
<std macros>:3:1: 3:54 note: in this expansion of print! (defined in <std macros>)
example.rs:19:9: 19:36 note: in this expansion of println! (defined in <std macros>)
example.rs:19:33: 19:34 help: run `rustc --explain E0277` to see a detailed explanation
example.rs:19:33: 19:34 help: consider adding a `where T : core::fmt::Debug` bound
example.rs:19:33: 19:34 note: required by `core::fmt::Debug::fmt`

The core::fmt::Debug is going to become std::fmt::Debug as soon as https://github.com/rust-lang/rust/pull/32439 lands.


#10

I see. Thank you. It is better. May be I am wrong on nit picking on this part, but to be honest this was more confusing for me:

This is telling me that Debug is not implemented, while in practice, the compiler doesn’t care about what is implemented, it cares about what the constraint was for T. This may be obvious for everyone else, but for me this is telling me that I need to do something with T and thus i, rather than adding a constraint trait in the generics declaration.


#11

I don’t like that error message too. Maybe change it to (bikeshed):

unmet trait predicate: `T : core::fmt::Debug`

and have “consider adding a where-clause”?

I am not so sure about that. If someone can find a nice way to word it we will go with that.


#12

That would be helpful! I like that a lot.

May be this way?:

type `T` has unmet trait predicate: `core::fmt::Debug`


#13

The trait predicate is T : core::fmt::Debug - that’s a technical term.


#14

In that case, should the help be “consider adding a where-clause”?


#15

I’d reword the message as:

type T allows types that don’t implement the core::fmt::Debug trait

and +1 to “consider adding where T: core::fmt::Debug clause”


#16

Variant I want:

ERROR: the predicate `T : core::fmt::Debug` is not satisfied
HELP: consider adding a where-clause

what do you think of it?


#17

I’d prefer it without the word “predicate”, which adds to the techno-jargon of the message.


#18

I need something to start the sentence with.


#19

“Constraint” and “bound” are two other terms that are commonly used. I don’t know if either of them sound more friendly.


#20

I see. How about to put an explanation there for the ones who are not familiar with the term. Or just add another line saying this in my case:

Hint: consider changing the declaration to 'impl<T : fmt::Debug> Info for Buffer<T>'

For me this would be the easiest to understand.