{"action":"created","issue":{"url":"https://api.github.com/repos/ambv/typehinting/issues/1","labels_url":"https://api.github.com/repos/ambv/typehinting/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/ambv/typehinting/issues/1/comments","events_url":"https://api.github.com/repos/ambv/typehinting/issues/1/events","html_url":"https://github.com/ambv/typehinting/issues/1","id":45926771,"number":1,"title":"How to declare type variables","user":{"login":"gvanrossum","id":2894642,"avatar_url":"https://avatars.githubusercontent.com/u/2894642?v=3","gravatar_id":"","url":"https://api.github.com/users/gvanrossum","html_url":"https://github.com/gvanrossum","followers_url":"https://api.github.com/users/gvanrossum/followers","following_url":"https://api.github.com/users/gvanrossum/following{/other_user}","gists_url":"https://api.github.com/users/gvanrossum/gists{/gist_id}","starred_url":"https://api.github.com/users/gvanrossum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gvanrossum/subscriptions","organizations_url":"https://api.github.com/users/gvanrossum/orgs","repos_url":"https://api.github.com/users/gvanrossum/repos","events_url":"https://api.github.com/users/gvanrossum/events{/privacy}","received_events_url":"https://api.github.com/users/gvanrossum/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2014-10-15T22:16:15Z","updated_at":"2015-01-07T19:48:39Z","closed_at":null,"body":"There are two issues around type variables:\r\n\r\n- What function to call a type variable\r\n- How to specify constraints (and what do the constraints mean)\r\n\r\nCurrently, mymy uses\r\n```\r\nT = typevar('T', values=[t1, t2, t3])\r\n```\r\nwhile the PEP currently proposes\r\n```\r\nT = Var('T', t1, t2, t3)\r\n```\r\nIn any case it should be noted in the PEP that this is *not* the same as\r\n```\r\nT = Union[t1, t2, t3]\r\n```\r\nThe reason is quite subtle, and the best example is currently the predefined type variable\r\n```\r\nAnyStr = Var('AnyStr', bytes, str)\r\n```\r\nConsider a polymorphic function that does something to filenames and works on both bytes and str, e.g.\r\n```\r\ndef extension(file: AnyStr) ->AnyStr:\r\n   return file.rsplit(b'.' if isinstance(file, bytes) else '.', 1)[1]\r\n```\r\nWe really need AnyStr to be a type variable here, because we want to express that if the argument is a bytes, so is the return value, and if the argument is a str, the return value is too.\r\n\r\nBut that's not all! Such a type variable is constrained to *exactly* the given types. Consider the case where the argument is an instance of a user-defined subclass of bytes. We don't want the declaration to mean that the return value is then also an instance of that same subclass -- we want it to mean that the return value is a bytes (not a str).\r\n\r\nI believe this makes the use of such a type variable equivalent to a collection of overloaded functions; in the above example\r\n```\r\ndef extension(file: bytes) -> bytes:\r\n    ...\r\ndef extension(file: str) -> str:\r\n    ...\r\n```\r\nOpen issues:\r\n\r\n- What should the rules be if the type variable is unconstrained?\r\n- Other languages often have a syntax for specifying a different type of constraint on type variables, e.g. the presence of a certain method; and then the implied type usually does vary with the actually specified type (I think). Do we need a way to do this?\r\n- Should we name this Var(), typevar(), or something else? (Var() is a PEP 8 violation.)\r\n- Should the constraints be additional positional arguments, or a keyword argument? If the latter, what should it be named?"},"comment":{"url":"https://api.github.com/repos/ambv/typehinting/issues/comments/69080184","html_url":"https://github.com/ambv/typehinting/issues/1#issuecomment-69080184","issue_url":"https://api.github.com/repos/ambv/typehinting/issues/1","id":69080184,"user":{"login":"gvanrossum","id":2894642,"avatar_url":"https://avatars.githubusercontent.com/u/2894642?v=3","gravatar_id":"","url":"https://api.github.com/users/gvanrossum","html_url":"https://github.com/gvanrossum","followers_url":"https://api.github.com/users/gvanrossum/followers","following_url":"https://api.github.com/users/gvanrossum/following{/other_user}","gists_url":"https://api.github.com/users/gvanrossum/gists{/gist_id}","starred_url":"https://api.github.com/users/gvanrossum/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gvanrossum/subscriptions","organizations_url":"https://api.github.com/users/gvanrossum/orgs","repos_url":"https://api.github.com/users/gvanrossum/repos","events_url":"https://api.github.com/users/gvanrossum/events{/privacy}","received_events_url":"https://api.github.com/users/gvanrossum/received_events","type":"User","site_admin":false},"created_at":"2015-01-07T19:48:39Z","updated_at":"2015-01-07T19:48:39Z","body":"I explained the naming/syntax issue in https://github.com/ambv/typehinting/issues/5 (I hope).\r\n\r\nmypy currently doesn't like something like Iterable[X] as a typevar constraint (the 'values=' kwarg). This may be because it doesn't support parametrized types as type aliases; e.g. this fails:\r\n```\r\nX = typevar('X')\r\nY = Iterable[X]\r\n```\r\nI propose that in the first published draft of the PEP we use a simpler example that actually works when translated to mypy syntax, and think more deeply about constraints on type variables a bit later. E.g. this works as an example using Callable and generic types:\r\n```\r\nX = TypeVar('X')\r\ndef filter(pred: Callable[[X], bool], input: Iterable[X]) -> Iterable[X]:\r\n      return [x for x in input if pred(x)]\r\n```\r\nFor constrained types it would be better to discuss the AnyStr example in the PEP."}}