-
Notifications
You must be signed in to change notification settings - Fork 258
Alternative notations for covariance and contravariance #211
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
Comments
I'm sorry, this instantly gave me a headache. I don't even understand what's wrong with
Surely you meant "a subtype of Mapping[t, int]" ?
IIRC in #115 we said that if Generic[...] is listed as a base class, only the variables mentioned there are valid, and their order is determined by that form (not by the default rule of picking them out of all bases in textual order).
I'm not sure that's one of our goals. I think it would be more important if it could be made understandable for people like myself. |
This is exactly my point. There is nothing wrong formally with such definition, but such examples constantly confuse me, since the type variable here contains the variance information that is redundant in this context. Such redundant information never appears with the +/- notations.
Yes, that is a typo.
You are right. I am sorry, this is a bad example. I just wanted to illustrate that both longer (with
I agree. But I think I am more like you than like that other people :-) and +/- in generic type declaration is much more understandable for me than What do you you think? Is +/- notation is more understandable for you than |
TBH any mention of variance gives me a headache, which doesn't sound like it's the case for you. :-) So I'm not sure what to think of the +T/-T notation. I'm not even sure I could remember which of these means co and which one is contra. Regarding the function with unwanted variance information, I don't see why a type checker couldn't reject that just as easily as it would reject use of +T/-T. Regardless, it's not something one would write unless one is still learning stuff, and typing random programs and responding to the error messages is a really poor way to learn about something as abstract as variance. (I personally figured out the reason just now by starting to type a program, and before I had even finished it I understood the reason why variance is silly here.) |
Note that the implementation of variance in mypy is not complete, which mostly means that mypy won't reject many things that it should complain about. |
@JukkaL I understand your point. I just wanted to raise the question at an early stage, when it is easy to change things. BTW, what do you think about indicating variance only in generic type declaration instead of indicating it in the type variable definition?
@gvanrossum , Agreed. Still, there is the question what to do with the situations where type variable is covariant or contravariant but has a non-self-descriptive name. I think +/- notation forces you to indicate the variance information exactly where it is necessary and that could improve readability significantly. Of course one could make some convention on naming of type variables, but it is a bit ugly |
@gvanrossum By the way, there is a simple mnemonic rule to remember which of +/- means co and which one is contra. Consider a function |
@rwbarton Could you please tell your opinion on the idea proposed in this issue? |
I agree that it would make more sense to specify the variance of generic class type variables at the class definition site. As for the concrete syntax I thought of the more explicit syntax class MyClass(Generic[T, U, S], Covariant[T], Contravariant[S], Mapping[T, int], Set[S]):
... But a subclass of |
Maybe this instead? class MyClass(Generic[Covariant[T], U, Contravariant[S]], T, S, Mapping[T, int], Set[S]):
... I still think that a naming convention like |
The good point for As a yet another alternative, I would propose: class MyClass(Generic[Co[T], U, Contra[S]], Mapping[T, int], Set[S]):
... This is only slightly more verbose than naming convention, but at the same time it is more clear to specify the variance at the class definition site. @rwbarton @gvanrossum what do you think? |
I could see
And I have many other more pressing things to do. |
If we have an agreement on this, then I could implement Or do you think we need to first ask other guys (from pytype and PyCharm) whether they have any objections? |
You have it backwards. If we are going to change this, Co/Contra are |
@gvanrossum OK, I see. Actually, I feel similar about this issue. I could live with the current situation, but I am more worried about people who are not familiar with variance. After some thinking I have a radically different alternative proposal: keep only the current syntax, but
|
That sounds like a plan I can get behind. Do you have the oomph to write up On Tue, Aug 2, 2016 at 1:07 AM, Ivan Levkivskyi [email protected]
--Guido van Rossum (python.org/~guido) |
OK, if @rwbarton also has no objections I will submit a PR to python/peps tomorrow and later also a patch for documentation at docs.python.org |
Yes, this sounds like a good plan to me too. (I actually think it would still be a minor improvement to mypy to internally make the change suggested in the original post, of moving variance from an attribute of a type variable to an attribute of a class definition. This would just be a refactoring though, and is low priority.) |
I have submitted two PRs: here #257 and to python/peps. |
I was referred here from python-ideas. Just wanted to comment on Guido's statement
I remember very well that as a 3rd-year student, it took me (and many others) too long to memorize what does "covariance" and "contravariance" mean. Maybe that's more obvious to people from Europe/America, but it is a non obvious terminology. Yes, it is standard, but +T/-T is now standard in Scala, and much less verbose; generic type names are already too verbose. |
NOTE: The Idea described here was discussed in the context of #2 , but somehow was forgotten.
Here I would like to revive the discussion of this particular idea.
I was writing a text explaining variance of generic types and I have found something that is quite inconvenient and confusing form me in the current notations for variance. The key point is that covariance, contravariance, or invariance are the properties of generics, not of type variables. As currently agreed, only the declaration-site variance is supported. Yet, something like this is currently not prohibited by the PEP:
It is quite unclear what that would mean. There is another problem, if one sees a type variable, then unless it has a self-explanatory name, it is not clear whether it is covariant, invariant, or contravariant, one needs to scroll up to its definition.
I would like to propose to change slightly the notation. Namely, remove
covariant
andcontravariant
keyword arguments fromTypeVar
constructor. Instead, implement__pos__
and__neg__
methods for unary plus and minus. Pluses and minuses should be allowed only in the definition/declaration of a generic type. So that one could writeand this would mean that:
MyClass[t, u, s]
is a subtype ofMapping[t, int]
and a subtype ofSet[s]
, i.e. could be used in place of function parameters with such declared types.MyClass[t1, u, s]
is a subtype ofMyClass[t2, u, s]
ift1
is a subtype oft2
(covariance).MyClass[t, u, s2]
is a subtype ofMyClass[t, u, s1]
ifs1
is a subtype ofs2
(contravariance).MyClass
is invariant in second type argument.Also, as discussed in #115 a shorter notation (ommiting
Generic
) could be used in simple cases:At the same time, pluses and minuses in type annotations of functions and variables should be prohibited by the PEP:
I think that the new notation would be especially clearer in situation with complex indexed generic types. One could be easily confused by
how could it be contravariant if
Iterator
is defined as covariant? Such confusions will be eliminated with the new notations. Also, it would be simpler to understand for people familiar with other languages like C#, Scala or OCaml.EDITED: there was a typo in point 1, and a mistake in the short example
The text was updated successfully, but these errors were encountered: