Looking for feedback on an improved error message for E0308

Hi folks, I'm working on improving the error message for E0308. In this post, I'm hoping I can get some feedback on the wording I'm working on. I'm a new contributor to Rust, and I'm nervous about changing the error message so many will see when editing their code.

It's the error message when two different types seem to be assigned to the same variable. (Which doesn't work in a static language as I understand it. I'm a bit of a perpetual beginner to programming...)

I thought the old message was a bit wordy and intimidating, but that it could be communicated in a clearer way without losing any accuracy.

I just did this PR that got merged: https://github.com/rust-lang/rust/pull/70242/files

But I'm still a bit unsatisfied with how it turned out.

(I don't want to change the code snippet in the error message, because I think it's good. I'm focused only on the wording of the message.)

Here's my latest draft:

This error occurs when the compiler was unable to infer the concrete type of a variable. It can occur for several cases; The most common case is a mismatch between two types: the type explicitly assigned to a variable by the [code's] author, and the type the compiler infers for an expression assigned to that variable.

I'm not sure about the phrase "the code's author" being maybe too verbose... and I'm not sure if I want to add this at the end of the last sentence:

assigned to that variable [later on].

Or:

for an expression [to be assigned] to that variable.

I also want to add a "hint" sentence on to the end, explaining that this error exists due to Rust being a statically-typed language. This error seemed like a pretty foreign concept to me when I first saw it, because I'm used to dynamic typing. I have taken a few approaches to wording this, and I'm not sure which I prefer.

No variable may have more than one type during the same program, as Rust is statically typed.

A single variable may not have more than one type during the same program, as Rust is statically typed.

A single variable may not have more than one type, as Rust is a statically typed language.

A variable may not take on a second type after it has been initialized with a first type. (Rust is a statically typed language.)

Can anyone give me their thoughts on this? Suggested improved wording? Can you confirm my wording choices are accurate? Is it okay I took out the concept of "initialization," from the main error text, or would most programmers get better information with that included?

Thanks for any feedback.

Also: I'm interested in starting up an effort to improve the existing error messages and docs, and sort of set an example of clear yet approachable language around the Rust language. If anyone has ideas on how to do this or wants to join in, feel free to get in touch.

2 Likes

@TomP Thanks for the suggestion. I take that as being a proposed wording for the "hint" lines at the end.

That's nice and concise, and I trust that it's accurate. But its conciseness is partly due to not explaining what the difference between static and dynamic typing is.

As a beginner, I might not know what that means... I also might now "know what I don't know" enough to be confident doing a web search about it. I figure anyone who actually runs rustc --explain E0308 is mystified enough that a little more explanation is worth it.

But at the same time, more-advanced programmers might feel it's unnecessary, or too much hand-holding? ("painfully obvious"?) So I don't want to totally ignore their opinions either...

Would love some varied opinions in here so I can gauge the consensus. But at the end of the day (figuratively -- I'll take the time to get this right as long as I'm receiving replies) I'll submit the best I have as a second PR.

I don't feel that it's the job of Rust error messages to teach programming concepts. People who don't understand the terminology can use a search engine to find what the terminology means.

1 Like

I think E0308 is an error people will see a lot as they try to pick up the language, so the hint is justified in my personal opinion.

Edit to add: I realized, when trying to capture the essence of this error code so I could improve the wording, that it's basically just "follow the rules of static typing, please." If you don't understand static typing, the error message makes no sense. So that's why I think a short sentence or two of explaining static typing is worthwhile and appropriate. Meeting the programmer where they're at.

I feel like within the length of prose already used, since before I got involved, these concepts can be referred to.

On the other hand, I've heard a couple of times so far (on Reddit) that error messages shouldn't "teach" programming concepts.

I do feel there's a missing piece of explanation in the Rust ecosystem that teaches these basic concepts. C resources often do explain programming concepts, as it's assumed to be the coder's first language. IMO a user trying to learn Rust as a beginner is less lucky in that regard...

If consensus is against it, I'll have to leave it out. My first instinct is to briefly touch on the meaning of static typing, though.

If all error messages assumed that rationale, error messages about lifetimes should try to teach about lifetimes. Likewise for traits, etc. Why not just provide a subcluse number for the appropriate part of TRPL as guidance for people who are trying to program in Rust without first studying the documentation?

1 Like

If you're suggesting linking to The Book™, that might be a reasonable compromise. (I couldn't tell if you were sincerely for, or sarcastically against that.)

The problem being, The Book doesn't really explain static typing clearly, either!

Keep in mind that Rust is a statically typed language, which means that it must know the types of all variables at compile time.

This is the only mention of static typing I am aware of in The Book. It is not very explicit that a single variable may not have more than one type. If that much isn't clear, the user has to do a web search, hopefully find a clear explanation, maybe just give up... I don't want to send the reader of my error message text on a wild goose chase. It feels like a few dozen bytes of text is a fair price to pay in order to hint that a variable can't have more than one type. Anything short of such a direct explanation feels like innuendo or charades.

As for my previous point, my thinking was that some errors are more likely to be seen by beginners to programming/Rust in general. And other errors that involve more advanced concepts might assume a more-advanced reader.

Some amount of human judgment and leeway toward error message content is okay, rather than hard and fast rules, as long as it doesn't get out of hand or become an ongoing problem.

I doubt a reviewer at GitHub would ask me to remove such a brief explanation of static typing. I am ideologically opposed to withholding that information from readers on the basis of "not teaching programming concepts" as if that were a virtue. (I feel the opposite, that teaching is a virtue.) IMO it is on-topic and very brief, and therefore shouldn't be offensive, even to advanced readers. We all were beginners at one point...

My suggestion was sincere, not facetious. There are many aspects of Rust that are difficult to learn, depending on one's prior programming experience. I mentioned lifetimes and traits because those differ from most programming language experience. It makes sense to enhance many error messages for nauplii (new crustaceans) by adding one or more references to subclauses of TRPL, which is the offical Rust documentation. (For more esoteric topics the Rustonomicon may be the appropriate reference.)

For the specific topic of E0308, if the book explanation is too minimal, as your research seems to indicate, then it is the book that needs a better explanation of the topic. That, coupled with a reference to an appropriate subclause of the book, should suffice for E0308. The same approach can be applied anywhere else that the existing documentation is deemed insufficient.

1 Like

Thanks for the considered response. I think that's reasonable, and I can probably tweak The Book a bit.

My last remaining concern is that The Book states in the introduction that it expects you to have learned programming in general by learning another language.

This book assumes that you’ve written code in another programming language but doesn’t make any assumptions about which one. We’ve tried to make the material broadly accessible to those from a wide variety of programming backgrounds. We don’t spend a lot of time talking about what programming is or how to think about it. If you’re entirely new to programming, you would be better served by reading a book that specifically provides an introduction to programming.

Thus, to learn Rust, I must first learn C, Python, Ruby or JavaScript etc. etc. and then come back and learn Rust. (Assuming I want to use the best Rust resource, The Rust Programming Language.)

Maybe I'm on my own, but I'd like to think lots of other people want to learn Rust as a first language... Maybe I'll just have to write such a resource myself one of these days. But that's arguably off-topic. So I'll mull over any improvements I can make to the [error message] text (without an aside to fundamentally explain static programming, I suppose).

@tomp may I use your suggested text in my Pull Request?

If so, should I credit you, and in what way?

Of course you [Edit: can^H^H^Hmay] use it, preferably without credit. Lots of us contribute to discussions on open forums. No credit is expected, or needed.

@DeeDeeG If you would like, you could help to tweak the book for be suitable for beginners too, I could this of adding sort of a beginners note on each section to mention terminology to beginners such as variables, pass by value, pass by reference, lifetime, traits, structures, enums, types and a bunch of other stuff which may interest beginners.

Yes, there are a lot of work that needs to be done. But having a beginner to review those may be hard since people who came into rust usually already know another language. Maybe you might need to review it yourself (from what I see, you came into rust directly) or ask some kids to review it and see if they understand.

I am not from the docs team but I think you might want to ask them for suggestions before doing this, they could be found from #docs in rust discord https://www.rust-lang.org/community.

2 Likes

Thanks for the response.

I have been thinking a "picking up programming through Rust" backgrounder book would be a good complement to The Book.

For one thing, The Book is pretty explicit about not being a resource for first-time programmers. I respect that up-front scope-setting and I don't intend to shoehorn all the basics into The Book.

As for what I'd like to see as a complement to the book: There's "learning all programming language concepts in a universal way" (huge scope, hard to be accurate about all programming languages at once...) Or "here's what you need to know to understand Rust/The Book." I prefer the latter. It's more manageable and a closer match to my interest area.

There's beginner resources for e.g. Python or C, but not so much for Rust. (As far as I can tell.)

I think the work to be done here is too complex to be done over Discord, though maybe some folks' attention could be got or they could be recruited to the effort there once the ball got rolling. So it's a good suggestion. I hadn't considered the Discord before, but now I will think of it if I need to reach out.

2 Likes

While I have your attention, any feedback about the updated error message I suggested here would be appreciated!

Even if it's "yes/no". -- "Yes this suggestion is better than the current message in master" or "No, this is worse."

[Edit to clarify: Last I checked, this error message hasn't been updated in master after my PR landed. master matches my PR.]

I like hearing multiple takes and I prefer forming a group consensus where possible! There is no obligation, but I would appreciate it.

I came up with a message with much simpler language, but still accurate. (To the best of my knowledge).

Expected type did not match the received type.

Erroneous code example:

let x: i32 = "I am not a number!";
//     ~~~   ~~~~~~~~~~~~~~~~~~~~
//      |             |
//      |    initializing expression;
//      |    compiler infers type `&str`
//      |
//    type `i32` assigned to variable `x`

This error occurs when two different types are assigned to the same variable.

In the example above, the type "i32" is explicitly assigned to the variable "x".
Then, the expression "I am not a number!" (which is inferred by the compiler
to have the type "&str") is also assigned to the variable "x".

In the example, this error occurs because the types "i32" and "&str"
are different from one-another, but both types are assigned to the same variable
"x".

(In Rust, each variable may have only type; Rust is a statically typed language.
Dynamic typing is not supported.)

(To create a new variable, re-using an existing variable name,
but with the option of assigning a different type, see shadowing:
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing)

It's a bit longer, but the part walking through the example snippet, and the part about shadowing, could easily be deleted to shorten the message:

[INTRODUCTION AND SNIPPET HERE]

This error occurs when two different types are assigned to the same variable.

In the example above, this error occurs because the types "i32" and "&str"
are different from one-another, but both types are assigned to the same variable
"x".

(In Rust, each variable may have only type; Rust is a statically typed language.
Dynamic typing is not supported.)

Or even just:

[INTRODUCTION AND SNIPPET HERE]

This error occurs when two different types are assigned to the same variable.

(In Rust, each variable may have only type; Rust is a statically typed language.
Dynamic typing is not supported.)

If anyone is in favor if one of these drafts of the message, please let me know. I'd like to propose it in a PR, but as in this whole thread, I like to get feedback on these things. (I am personally very happy with this wording for being approachable and direct.)

Otherwise, I would plan on submitting a PR with the wording I posted earlier in this thread.

For reference, the original message from before my changes:

Expected type did not match the received type.

Erroneous code example:

let x: i32 = "I am not a number!";
//     ~~~   ~~~~~~~~~~~~~~~~~~~~
//      |             |
//      |    initializing expression;
//      |    compiler infers type `&str`
//      |
//    type `i32` assigned to variable `x`

This error occurs when the compiler was unable to infer the concrete type of a
variable. It can occur for several cases, the most common of which is a
mismatch in the expected type that the compiler inferred for a variable's
initializing expression, and the actual type explicitly assigned to the
variable.

Maybe this is just me, but this sentence sounds factually incorrect to me. I know "dynamic typing" is a fuzzy term that can mean a lot of things, but it seems like type erasure and runtime polymorphism through Rust's trait objects would qualify. Perhaps that is "opt-in dynamic typing". Regardless, to say it is "not supported" makes it sound more like a missing feature than a design decision.

Just "(In Rust, each variable may have only type; Rust is a statically typed language.)" seems good to me.

I think what this sentence is trying to say adds value to the message, but the way it's saying it feels excessively verbose, in the way that sometimes leads novices to confuse themselves by reading too much into it. How about just:

In the example above, an "i32" value and a "&str" value are both assigned to the same variable "x".

1 Like

Thanks for the feedback, I agree with your points.

As for this wording:

In the example above, an "i32" value and a "&str" value are both assigned to the same variable "x".

Trying to be 100% accurate, I think the snippet's let x: i32 doesn't involve an i32 "value", just a type assignment.

So I tweaked the sentence a bit, and I think this works:

In the example above, the types "i32" and "&str" are both assigned to the same variable "x".


Long version with updated wording:

[INTRODUCTION AND SNIPPET HERE]

This error occurs when two different types are assigned to the same variable.

In the example above, the type "i32" is explicitly assigned to the variable "x".
Then, the expression "I am not a number!" (which is inferred by the compiler
to have the type "&str") is also assigned to the variable "x".

In the example, the types "i32" and "&str" are both assigned to the same variable "x".

(In Rust, each variable may have only type; Rust is a statically typed language.)

(To create a new variable, re-using an existing variable name,
but with the option of assigning a different type, see shadowing:
https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing)

Now these two paragraphs feel awfully similar. I think we can combine them into something like this:

I can agree the paragraphs were too similar. As you can tell, I do like to be pretty explicit with the cause-and-effect of things. Even when it's a bit repetitive. But I'm not sure I could combine the paragraphs any better than that myself.

There's a trade-off between explicitness/clunkiness, versus readability, but hopefully that just means this is running into the limits of being improved.

(The other option I can think of is to drop one or the other paragraph.)