{"action":"created","issue":{"url":"https://api.github.com/repos/rust-lang/rfcs/issues/1210","repository_url":"https://api.github.com/repos/rust-lang/rfcs","labels_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1210/labels{/name}","comments_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1210/comments","events_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1210/events","html_url":"https://github.com/rust-lang/rfcs/pull/1210","id":94822300,"number":1210,"title":"RFC: impl specialization","user":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/rust-lang/rfcs/labels/final-comment-period","name":"final-comment-period","color":"207de5"},{"url":"https://api.github.com/repos/rust-lang/rfcs/labels/T-lang","name":"T-lang","color":"bfd4f2"}],"state":"open","locked":false,"assignee":{"login":"aturon","id":709807,"avatar_url":"https://avatars.githubusercontent.com/u/709807?v=3","gravatar_id":"","url":"https://api.github.com/users/aturon","html_url":"https://github.com/aturon","followers_url":"https://api.github.com/users/aturon/followers","following_url":"https://api.github.com/users/aturon/following{/other_user}","gists_url":"https://api.github.com/users/aturon/gists{/gist_id}","starred_url":"https://api.github.com/users/aturon/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aturon/subscriptions","organizations_url":"https://api.github.com/users/aturon/orgs","repos_url":"https://api.github.com/users/aturon/repos","events_url":"https://api.github.com/users/aturon/events{/privacy}","received_events_url":"https://api.github.com/users/aturon/received_events","type":"User","site_admin":false},"milestone":null,"comments":258,"created_at":"2015-07-13T22:00:51Z","updated_at":"2016-02-03T09:30:31Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/rust-lang/rfcs/pulls/1210","html_url":"https://github.com/rust-lang/rfcs/pull/1210","diff_url":"https://github.com/rust-lang/rfcs/pull/1210.diff","patch_url":"https://github.com/rust-lang/rfcs/pull/1210.patch"},"body":"This RFC proposes a design for *specialization*, which permits multiple `impl`\r\nblocks to apply to the same type/trait, so long as one of the blocks is clearly\r\n\"more specific\" than the other. The more specific `impl` block is used in a case\r\nof overlap. The design proposed here also supports refining default trait\r\nimplementations based on specifics about the types involved.\r\n\r\nAltogether, this relatively small extension to the trait system yields benefits\r\nfor performance and code reuse, and it lays the groundwork for an \"efficient\r\ninheritance\" scheme that is largely based on the trait system (described in a\r\nforthcoming companion RFC).\r\n\r\n[Rendered](https://github.com/aturon/rfcs/blob/impl-specialization/text/0000-impl-specialization.md)"},"comment":{"url":"https://api.github.com/repos/rust-lang/rfcs/issues/comments/179120245","html_url":"https://github.com/rust-lang/rfcs/pull/1210#issuecomment-179120245","issue_url":"https://api.github.com/repos/rust-lang/rfcs/issues/1210","id":179120245,"user":{"login":"nikomatsakis","id":155238,"avatar_url":"https://avatars.githubusercontent.com/u/155238?v=3","gravatar_id":"","url":"https://api.github.com/users/nikomatsakis","html_url":"https://github.com/nikomatsakis","followers_url":"https://api.github.com/users/nikomatsakis/followers","following_url":"https://api.github.com/users/nikomatsakis/following{/other_user}","gists_url":"https://api.github.com/users/nikomatsakis/gists{/gist_id}","starred_url":"https://api.github.com/users/nikomatsakis/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/nikomatsakis/subscriptions","organizations_url":"https://api.github.com/users/nikomatsakis/orgs","repos_url":"https://api.github.com/users/nikomatsakis/repos","events_url":"https://api.github.com/users/nikomatsakis/events{/privacy}","received_events_url":"https://api.github.com/users/nikomatsakis/received_events","type":"User","site_admin":false},"created_at":"2016-02-03T09:30:31Z","updated_at":"2016-02-03T09:30:31Z","body":"@sgrif \r\n\r\n> IIRC the rules are roughly that you can only rely on the concrete type when it doesn't cross crate boundaries. \r\n\r\nI'm not really sure what you mean by this. I don't think there is anything in the rules today about cross-crate boundaries today when it comes to associated type projection. I think you may be referring to the rules on negative reasoning in coherence, which do consider local and cross-crate scenarios differently.\r\n\r\n> Regardless, it seems like the simplest (from the user point of view) thing to do here is -- if you are in a context where you know the type cannot be specialized further, you're allowed to rely on it.\r\n\r\nBut this is not what would happen. Rather, it's (almost) the opposite. That is, imagine that I have a trait `SomeTrait` and a type `SomeType`, and I implement `SomeTrait` for `SomeType`, with a specializable binding of `Output` to `char`:\r\n\r\n```rust\r\n// Crate A\r\ntrait SomeTrait<T> { type Output; }\r\n\r\nstruct TypeA { .. }\r\nimpl SomeTrait<T> for TypeA {\r\n    default type Output = char;\r\n}\r\n```\r\n\r\nSo, that means that e.g. `<TypeA as SomeTrait<i32>>::Output` would be resolved to `char`. Now, some other crate could come along and specialize one particular case, changing the `Output` binding for `<TypeA as SomeTrait<TypeB>>::Output` to `String`.\r\n\r\n```rust\r\n// Crate B\r\nstruct TypeB;\r\nimpl SomeTrait<TypeB> for TypeA {\r\n    default type Output = String;\r\n}\r\n```\r\n\r\nTo account for this possibility, any generic code that is attempting to normalize `<TypeA as SomeTrait<U>>::Output` where it does not know precisely what `U` is would have to leave the\r\nresult as a projection (that is, unnormalized), even in the original crate. In particular you could not normalize it to `char`. \r\n\r\nBut the question is, what about projections where there are NO type variables involved, like `<TypeA as SomeTrait<i32>>::Output`? Should we able to resolve *that* to `char`? On the one hand, no downstream crate could ever change it, because of the orphan rules (and we rely on that fact to be able to generate code, so it is not going to change). On the *other* hand, if the original crate can rely on it, then so can downstream crates, which means that now the original crate cannot later add a specialization that would change it:\r\n\r\n```rust\r\n// Crate A, some time later\r\nimpl SomeTrait<i32> for TypeA {\r\n    default type Output = String;\r\n}\r\n```\r\n\r\nThis seems asymmetric. That is, downstream crates can add specializations for types they control, but the original crate cannot (unless that type is newly introduced). For this reason at the moment I too lean towards leaving default types unresolved during type checking, even when all types are known.\r\n"}}