{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/220","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/220/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/220/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/220/events","html_url":"https://github.com/dotnet/roslyn/issues/220","id":56448961,"number":220,"title":"Add support for InternalImplementationOnly attribute","user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/dotnet/roslyn/labels/1%20-%20Planning","name":"1 - Planning","color":"cccccc"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Compilers","name":"Area-Compilers","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Area-Language%20Design","name":"Area-Language Design","color":"5319e7"},{"url":"https://api.github.com/repos/dotnet/roslyn/labels/Feature%20Request","name":"Feature Request","color":"fc2929"}],"state":"open","locked":false,"assignee":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"milestone":{"url":"https://api.github.com/repos/dotnet/roslyn/milestones/1","labels_url":"https://api.github.com/repos/dotnet/roslyn/milestones/1/labels","id":937397,"number":1,"title":"1.0 (stable)","description":"This is our 1.0 Milestone. ","creator":{"login":"jaredpar","id":146967,"avatar_url":"https://avatars.githubusercontent.com/u/146967?v=3","gravatar_id":"","url":"https://api.github.com/users/jaredpar","html_url":"https://github.com/jaredpar","followers_url":"https://api.github.com/users/jaredpar/followers","following_url":"https://api.github.com/users/jaredpar/following{/other_user}","gists_url":"https://api.github.com/users/jaredpar/gists{/gist_id}","starred_url":"https://api.github.com/users/jaredpar/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jaredpar/subscriptions","organizations_url":"https://api.github.com/users/jaredpar/orgs","repos_url":"https://api.github.com/users/jaredpar/repos","events_url":"https://api.github.com/users/jaredpar/events{/privacy}","received_events_url":"https://api.github.com/users/jaredpar/received_events","type":"User","site_admin":false},"open_issues":11,"closed_issues":7,"state":"open","created_at":"2015-01-15T20:45:24Z","updated_at":"2015-02-03T22:36:15Z","due_on":null,"closed_at":null},"comments":14,"created_at":"2015-02-03T22:36:15Z","updated_at":"2015-02-05T17:35:37Z","closed_at":null,"body":"InternalImplementationOnly attribute\r\n====================================\r\n\r\nOne difficulty that faces API authors is that sometimes an `interface` is the most appropriate type for an API element (because there are multiple unrelated implementations internally). However, once a public API element is exposed as an `interface` it would be a breaking change to add additional methods in a future revision of the interface (clients who implement the interface would be broken because they do not implement the new members).\r\n\r\nThis issue is mitigated when the API is intended to be implemented only by its authoring assemblies. However, there is no language mechanism to enforce that clients do not implement the interface. API authors resort to documentation suggesting that the interface not be implemented in customer code, but customers can fail to notice the documentation resulting in painful compatibility constraints that are unintended.\r\n\r\nThe Roslyn APIs have an example of this issue with the [`ISymbol`](http://source.roslyn.io/#Microsoft.CodeAnalysis/Symbols/ISymbol.cs) interface and all of its derived interfaces such as [`IMethodSymbol`](http://source.roslyn.io/#Microsoft.CodeAnalysis/Symbols/IMethodSymbol.cs) and [`INamedTypeSymbol`](http://source.roslyn.io/#Microsoft.CodeAnalysis/Symbols/INamedTypeSymbol.cs). We intend to evolve these interfaces in the future as the language changes, but we may be prevented from doing so because customer code may extend these interfaces.\r\n\r\nTo mitigate this compatibility constraint we propose to add a compiler-provided error. Interfaces such as `ISymbol` that should only be extended or implemented in assemblies that have internal access are marked with an attribute of the name [`System.Runtime.CompilerServices.InternalImplementationOnlyAttribute`](http://source.roslyn.io/#Microsoft.CodeAnalysis/InternalImplementationOnlyAttribute.cs).\r\n\r\n```cs\r\nnamespace System.Runtime.CompilerServices\r\n{\r\n    /// <summary>\r\n    /// Indicates that the interface may be implemented only by a type\r\n\t/// in the same assembly as the attributed interface or a type in\r\n\t/// an assembly that has InternalsVisibleTo the attributed interface's\r\n\t/// assembly.\r\n    /// </summary>\r\n    [AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)]\r\n    internal sealed class InternalImplementationOnlyAttribute : Attribute\r\n    {\r\n    }\r\n}\r\n```\r\n\r\nThis interface may be provided as a public type in a platform assembly, or as an internal type (as above) when the referenced platform does not yet provide direct support for the attribute.\r\n\r\nWhen a compiler sees that such an attributed interface is extended or implemented outside of an assembly that has internal access, a compile-time error is produced.\r\n\r\n```cs\r\nnamespace Microsoft.CodeAnalysis\r\n{\r\n    /// <summary>\r\n    /// Represents a symbol (namespace, class, method, parameter, etc.)\r\n    /// exposed by the compiler.\r\n    /// </summary>\r\n    [InternalImplementationOnly]\r\n    public interface ISymbol : IEquatable<ISymbol>\r\n    {\r\n```\r\n\r\nBy adding this attribute to interfaces such as `ISymbol`, an API author can have some confidence that future additions to the interface will not break compatibility with existing clients, as those clients will have been prevented from implementing the interface.\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/73089789","html_url":"https://github.com/dotnet/roslyn/issues/220#issuecomment-73089789","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/220","id":73089789,"user":{"login":"gafter","id":3804346,"avatar_url":"https://avatars.githubusercontent.com/u/3804346?v=3","gravatar_id":"","url":"https://api.github.com/users/gafter","html_url":"https://github.com/gafter","followers_url":"https://api.github.com/users/gafter/followers","following_url":"https://api.github.com/users/gafter/following{/other_user}","gists_url":"https://api.github.com/users/gafter/gists{/gist_id}","starred_url":"https://api.github.com/users/gafter/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gafter/subscriptions","organizations_url":"https://api.github.com/users/gafter/orgs","repos_url":"https://api.github.com/users/gafter/repos","events_url":"https://api.github.com/users/gafter/events{/privacy}","received_events_url":"https://api.github.com/users/gafter/received_events","type":"User","site_admin":false},"created_at":"2015-02-05T17:35:37Z","updated_at":"2015-02-05T17:35:37Z","body":"@tmat We do not generally introduce reverse breaking changes in the CLR without versioning the IL. It would not be OK to have code that runs on one version of the CLR but fails to run on an updated CLR that claims to support the same version."}}