rust-lang / nomicon

The Dark Arts of Advanced and Unsafe Rust Programming
https://doc.rust-lang.org/nomicon/
Apache License 2.0
1.75k stars 258 forks source link

The Subtyping and Variance chapter is confusing #339

Open mejrs opened 2 years ago

mejrs commented 2 years ago

Today in the Rust community discord we had a discussion about variance and the nomicon chapter discussing it (starting here), and how it's generally confusing and is something that just doesn't "click" for a lot of people (myself included).

First impression

I'll start off by summarizing my (and others') impressions as we read the chapter.

Subtyping is a relationship between types that allows statically typed languages to be a bit more flexible and permissive.

Uh, ok. This tells nothing about what subtyping is supposed to mean. (it's much later that this is actually explained)

Subtyping in Rust is a bit different from subtyping in other languages.

Well I don't know what "subtyping in other languages" is, either.

To keep things simple, this section will consider a small extension to the Rust language.... ...So here's our simple extension, Objective Rust

Seems kinda random how we got here. Why are we introducing a new language? I'm interested in what variance is in Rust and why I should care about it. This is anything but simple.

<lots of cats, dogs and animals>

At this point the article has completely lost me.

Constructive feedback

There are some things that could be done better:

Finally I would recommend you to read https://viralinstruction.com/posts/defense/. The author's frustration with teaching classes and inheritance is how I feel w/r to subtyping and variance.

rib commented 1 year ago

I've arrived at this chapter of the Rustonomicon a number of times when I've really wanted to try and clarify how to use the variance terms correctly when talking about Rust types and lifetimes and I have to admit I've found the chapter quite confusing, especially at the point where it starts talking about lifetimes.

I think the chapter sets you up for confusion by focusing on the concept of "subtypes" and "supertypes", and this note adds to that confusion imho:

NOTE: The typed-ness of lifetimes is a fairly arbitrary construct that some disagree with. However it simplifies our analysis to treat lifetimes and types uniformly.

because it sort of implies that only a minority disagree with the typed-ness of lifetimes - and once you read further I find it hard to agree that "it simplifies our analysis to treat lifetimes and types uniformly."

Digging back into some of the past discussions about lifetime variance, and some of the confusion that even existed within the compiler I found these two issues that seem very relevant here:

https://github.com/rust-lang/rfcs/issues/391 https://github.com/rust-lang/rust/issues/15699

Both of those seem conclude that it would be best to avoid thinking of lifetime variance in terms of subtyping and instead focus on the "outlives" relationship.

This paragraph in the rustonomicon shows there's an awareness of this source of confusion:

This is a large source of confusion, because it seems backwards to many: the bigger region is a subtype of the smaller region. But it makes sense if you consider our Animal example: Cat is an Animal and more, just as 'big is 'small

but the idea that that a bigger lifetime is a "subtype" based on thinking of it as a smaller region "and more" - like how a Cat is an Animal "and more" really doesn't make much sense to me personally. It seems like the rustonomicon is currently trying too hard to impart an intuitive understanding of lifetime variance in terms of subtyping that hinges on this "and more" idea, but at least for me this has never felt intuitive.

I have a feeling that the explanation of lifetime variance could be clearer if it was upfront about variance for lifetimes being based on a different kind of "outlives" relationship which isn't comparable to subtyping.

At least for me, based on reading the issues above I feel like things are clearer if I don't fight to think about how lifetime variance is like subtyping at all - and just thinking of it as having it's own rules, based on an "outlives" relationship.