Skip to content

The Subtyping and Variance chapter is confusing #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mejrs opened this issue Feb 9, 2022 · 1 comment
Open

The Subtyping and Variance chapter is confusing #339

mejrs opened this issue Feb 9, 2022 · 1 comment

Comments

@mejrs
Copy link

mejrs commented Feb 9, 2022

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:

  • Show locked doors before we show keys. We probably want to introduce basic subtyping (you can pass &'static Foo to fn bar<'a>(&'a Foo)), then show an issue with doing that (adapt the "meowing dogs" example to lifetimes) and then introduce variance to deal with this.
  • explain "is a subtype of" in terms of "is as useful as and more"
  • Possibly make readers read less cats and dogs before explaining it again in terms of lifetimes.
  • I think the author(s) underestimate how unintuitive cats, dogs and animals analogies actually are (see also the linked article below). Please don't use inheritance-y analogies.
  • The article dumps a lot of "we will explain this later" on the reader. Please don't underestimate how exhausting and confusing this is. For example there's an enormous distance between when variance is first mentioned and when it is explained.

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
Copy link

rib commented Feb 8, 2023

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:

rust-lang/rfcs#391
rust-lang/rust#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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants