{"action":"created","issue":{"url":"https://api.github.com/repos/python/mypy/issues/1284","repository_url":"https://api.github.com/repos/python/mypy","labels_url":"https://api.github.com/repos/python/mypy/issues/1284/labels{/name}","comments_url":"https://api.github.com/repos/python/mypy/issues/1284/comments","events_url":"https://api.github.com/repos/python/mypy/issues/1284/events","html_url":"https://github.com/python/mypy/issues/1284","id":139991532,"number":1284,"title":"Type aliases without implicit conversion (\"newtype\")","user":{"login":"gnprice","id":28173,"avatar_url":"https://avatars.githubusercontent.com/u/28173?v=3","gravatar_id":"","url":"https://api.github.com/users/gnprice","html_url":"https://github.com/gnprice","followers_url":"https://api.github.com/users/gnprice/followers","following_url":"https://api.github.com/users/gnprice/following{/other_user}","gists_url":"https://api.github.com/users/gnprice/gists{/gist_id}","starred_url":"https://api.github.com/users/gnprice/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnprice/subscriptions","organizations_url":"https://api.github.com/users/gnprice/orgs","repos_url":"https://api.github.com/users/gnprice/repos","events_url":"https://api.github.com/users/gnprice/events{/privacy}","received_events_url":"https://api.github.com/users/gnprice/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/python/mypy/labels/feature","name":"feature","color":"84b6eb"},{"url":"https://api.github.com/repos/python/mypy/labels/needs%20discussion","name":"needs discussion","color":"bfdadc"},{"url":"https://api.github.com/repos/python/mypy/labels/needs%20pep%20change","name":"needs pep change","color":"fbca04"}],"state":"open","locked":false,"assignee":null,"milestone":{"url":"https://api.github.com/repos/python/mypy/milestones/7","html_url":"https://github.com/python/mypy/milestones/Undetermined%20priority","labels_url":"https://api.github.com/repos/python/mypy/milestones/7/labels","id":1690406,"number":7,"title":"Undetermined priority","description":"Milestone for issues to which we can't assign a priority yet because we don't have enough information.","creator":{"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},"open_issues":3,"closed_issues":0,"state":"open","created_at":"2016-04-07T17:56:48Z","updated_at":"2016-04-07T18:43:36Z","due_on":null,"closed_at":null},"comments":19,"created_at":"2016-03-10T19:52:15Z","updated_at":"2016-04-07T18:44:27Z","closed_at":null,"body":"Several users (@wittekm among them) have asked for a feature where you can define something that's like a type alias in referring to an existing underlying type at runtime, but which isn't considered equivalent to it in the type-checker -- like what Hack and Haskell call `newtype`.\r\n\r\nOne classic application of this would be aliases/newtypes of `str` (or `unicode` or `bytes`) to distinguish fragments of HTML, Javascript, SQL, etc., from arbitrary text and enforce that conversions are only done with proper escaping, to prevent classes of vulnerabilities like XSS and SQL injection. A definition might look like `HtmlType = NewType(\"HtmlType\", str)`.\r\n\r\nOther classic uses include distinguishing identifiers of different things (users, machines, etc.) that are all just integers, so they don't get mixed up by accident.\r\n\r\nA user can always just define a class, say an empty subclass of the underlying type, but if an application is handling a lot of IDs or text fragments or the like, it costs a lot at runtime for them to be some other class rather than actual `str` or `int`, so that that isn't a good solution.\r\n\r\nThe main open question I see in how this feature might work is how to provide for converting these values to the underlying type. For a feature like this to be useful there has to be some way to do that -- so it's possible to write the conversion functions that take appropriate care like escaping text into HTML -- but preferably one that's private to a limited stretch of code, or failing that is at least easy to audit with `grep`. In Hack the types are implicitly equivalent just within the source file where the newtype is defined; in Haskell the newtype comes with a data constructor which is the only way to convert, and typically one just doesn't export that from the module where it's defined.\r\n\r\nThe Hack solution could work, and has the advantage that it means no run-time overhead at all, other than invoking the intended conversion functions that live in the newtype's file. It feels odd to me, though, because Python generally doesn't treat specially whether a thing is defined in a given module vs. imported into it. Another solution could be something like `html = HtmlType.make(text)` and `text = HtmlType.unmake(html)`, which would follow perfectly normal Python scoping and would be reasonably auditable.\r\n"},"comment":{"url":"https://api.github.com/repos/python/mypy/issues/comments/207045450","html_url":"https://github.com/python/mypy/issues/1284#issuecomment-207045450","issue_url":"https://api.github.com/repos/python/mypy/issues/1284","id":207045450,"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":"2016-04-07T18:44:27Z","updated_at":"2016-04-07T18:44:27Z","body":"I don't even know if this PEP change will go through, or when (even though I have it in the 3.5.2 milestone for the PEP -- that just means I want to think about it)."}}