Skip to content

Clarify generic function documentation #4618

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

Merged
merged 3 commits into from
Aug 1, 2018
Merged

Conversation

elias6
Copy link
Contributor

@elias6 elias6 commented Feb 21, 2018

This explains that a variable of a generic type must be able to be resolved to a non-generic type, hopefully preventing the confusion that made me (and possibly others) think #4590 is a bug.

@gvanrossum, I used some of the wording in your explanation almost verbatim. I'm guessing you don't mind.

This explains that a variable of a generic type must be able to be resolved to a non-generic type, hopefully preventing the confusion that made me (and possibly others) think python#4590 is a bug.

T = TypeVar('T') # Declare type variable

def first(seq: Sequence[T]) -> T:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need to repeat the two "good" examples -- this example should be only concerned with what doesn't work.

@@ -223,6 +223,26 @@ example we use the same type variable in two generic functions:
def last(seq: Sequence[T]) -> T:
return seq[-1]

Note that a variable cannot have a type variable in its type unless the type variable is bound in a containing generic class or function:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please break the long line. Also, maybe drop the leading "Note that" -- the previous section also starts like that and it's a bit repetitive.

@@ -223,20 +223,15 @@ example we use the same type variable in two generic functions:
def last(seq: Sequence[T]) -> T:
return seq[-1]

Note that a variable cannot have a type variable in its type unless the type variable is bound in a containing generic class or function:
A variable cannot have a type variable in its type unless the type
variable is bound in a containing generic class or function:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, sadly I just realized this is not quite correct, since this is possible:

T = TypeVar('T')
S = TypeVar('S')

def repeat(n: int) -> Callable[[Callable[[T], T]], Callable[[T], T]]:
    def outer(func: Callable[[S], S]) -> Callable[[S], S]:
        def inner(x: S) -> S:
            for i in range(n):
                x = func(x)
            return x
        return inner
    return outer

fff = repeat(3)
reveal_type(fff)  # 'def [T] (def (T`-1) -> T`-1) -> def (T`-1) -> T`-1'

But I don't want to include such an example here -- I just wish to find a way to write it that doesn't exclude it.

Also this much simpler example should be invalid but isn't:

def foo() -> T:
    pass

a = foo()

So I'm not sure what to do. Maybe @ilevkivskyi has an idea?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

def foo() -> T: pass

seems to be an unidiomatic way of writing

def foo() -> Any: pass

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They don't mean the same thing in mypy. The former returns a type containing <nothing> (meaning it has no values).

@elias6
Copy link
Contributor Author

elias6 commented Feb 22, 2018

@gvanrossum it seems like you don't need your strange nested example to contradict the wording in your explanation. I ran reveal_type on the first example in the "Generic functions" section of the documentation, and it told me Revealed type is 'def [T] (seq: typing.Sequence[T`-1]) -> T`-1'. I don't know exactly what that means, but isn't that an example of a type with a type variable, even though that type variable is not bound in a containing generic class or function?

I kind of have an idea of where and how type variables can and can't be used, based on the existing documentation and my own tinkering. But I can't imagine how to explain it precisely and rigorously, in a way that most mypy users will be able to understand. I think someone will have to help me with this.

@gvanrossum
Copy link
Member

Yeah, I went overboard with the complicated example. You'll note that all the examples where a type variable legitimately appears are types that are (or contain) generic functions. So maybe we should use that?

@gvanrossum
Copy link
Member

I propose to drop the example and just keep the sentence explaining the constraint. I'll just edit this myself so we can finish this up.

The actual errors are sufficiently different from what's shown that it's better not to show the example, IMO.
@gvanrossum gvanrossum merged commit 132dfa2 into python:master Aug 1, 2018
@gvanrossum
Copy link
Member

And, belatedly, thanks!

@elias6 elias6 deleted the generic_doc branch August 21, 2018 06:22
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

Successfully merging this pull request may close these issues.

3 participants