{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/11211","repository_url":"https://api.github.com/repos/dotnet/roslyn","labels_url":"https://api.github.com/repos/dotnet/roslyn/issues/11211/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/roslyn/issues/11211/comments","events_url":"https://api.github.com/repos/dotnet/roslyn/issues/11211/events","html_url":"https://github.com/dotnet/roslyn/issues/11211","id":153989311,"number":11211,"title":"Open classes/Virtual extension methods","user":{"login":"orthoxerox","id":8640149,"avatar_url":"https://avatars.githubusercontent.com/u/8640149?v=3","gravatar_id":"","url":"https://api.github.com/users/orthoxerox","html_url":"https://github.com/orthoxerox","followers_url":"https://api.github.com/users/orthoxerox/followers","following_url":"https://api.github.com/users/orthoxerox/following{/other_user}","gists_url":"https://api.github.com/users/orthoxerox/gists{/gist_id}","starred_url":"https://api.github.com/users/orthoxerox/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/orthoxerox/subscriptions","organizations_url":"https://api.github.com/users/orthoxerox/orgs","repos_url":"https://api.github.com/users/orthoxerox/repos","events_url":"https://api.github.com/users/orthoxerox/events{/privacy}","received_events_url":"https://api.github.com/users/orthoxerox/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":6,"created_at":"2016-05-10T12:00:56Z","updated_at":"2016-05-10T15:10:36Z","closed_at":null,"body":"I propose to extend \"extension everything\" (#11159) with virtual methods. In my opinion, the conservative approach of MultiJava should be good enough to handle most use cases and can be relaxed later.\r\n\r\n1. Virtual extension methods can be marked `virtual` and `override`. Extension methods cannot be marked `abstract` or `new`.\r\n\r\n2. Virtual extension methods cannot have interfaces or value types in the pseudo-receiver position.\r\n\r\n3. Virtual extension methods marked `override` must belong to the same static class as the virtual method being overridden.\r\n\r\n4. Virtual extension methods are automatically incorporated into the class bodies if all class bodies are declared in the same assembly as extension methods. A stub extension method remains in the static class where they've been described.\r\n```\r\nclass A { }\r\nclass B : A { }\r\nclass C : A { }\r\n\r\nclass FooExtension\r\n{\r\n    public virtual static int Foo(this A @this) => ...\r\n    public override static int Foo(this B @this) => ...\r\n    public override static int Foo(this C @this) => ...\r\n}\r\n\r\n//is transformed into\r\n\r\nclass A\r\n{\r\n    public virtual int Foo() => ...\r\n}\r\n\r\nclass B : A\r\n{\r\n    public override int Foo() => ...\r\n}\r\n\r\nclass C : A\r\n{\r\n    public override int Foo() => ...\r\n}\r\n\r\nclass FooExtension\r\n{\r\n    public static int Foo(A @this) => @this.Foo();\r\n}\r\n```\r\n\r\n\\5. Virtual extension methods that are declared in a different assembly than at least one of the classes being overridden are implemented as a typeswitch method with multiple private helper methods:\r\n```\r\nclass FooExtension\r\n{\r\n    public virtual static int Foo(this AnotherAssembly.A @this) => ...\r\n    public override static int Foo(this AnotherAssembly.B @this) => ...\r\n    public override static int Foo(this AnotherAssembly.C @this) => ...\r\n}\r\n\r\nclass FooExtension\r\n{\r\n    public static int Foo(this A @this)\r\n    {\r\n        switch (@this) {\r\n            case AnotherAssembly.B b:\r\n                return FooHelper(b);\r\n            case AnotherAssembly.C c:\r\n                return FooHelper(c);\r\n            default:\r\n                return FooHelper(a);\r\n        }\r\n    }\r\n    \r\n    private static int FooHelper(this AnotherAssembly.A @this) => ...\r\n    private static int FooHelper(this AnotherAssembly.B @this) => ...\r\n    private static int FooHelper(this AnotherAssembly.C @this) => ...\r\n}\r\n```\r\n\r\nThis approach solves the use case of sharing one inheritance hierarchy between two assemblies and using virtual dispatch in both. It doesn't solve use cases like adding your own efficient LINQ methods to specialized enumerables, but I think traits/higher-order generics will serve better."},"comment":{"url":"https://api.github.com/repos/dotnet/roslyn/issues/comments/218188451","html_url":"https://github.com/dotnet/roslyn/issues/11211#issuecomment-218188451","issue_url":"https://api.github.com/repos/dotnet/roslyn/issues/11211","id":218188451,"user":{"login":"HaloFour","id":10102290,"avatar_url":"https://avatars.githubusercontent.com/u/10102290?v=3","gravatar_id":"","url":"https://api.github.com/users/HaloFour","html_url":"https://github.com/HaloFour","followers_url":"https://api.github.com/users/HaloFour/followers","following_url":"https://api.github.com/users/HaloFour/following{/other_user}","gists_url":"https://api.github.com/users/HaloFour/gists{/gist_id}","starred_url":"https://api.github.com/users/HaloFour/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/HaloFour/subscriptions","organizations_url":"https://api.github.com/users/HaloFour/orgs","repos_url":"https://api.github.com/users/HaloFour/repos","events_url":"https://api.github.com/users/HaloFour/events{/privacy}","received_events_url":"https://api.github.com/users/HaloFour/received_events","type":"User","site_admin":false},"created_at":"2016-05-10T15:10:36Z","updated_at":"2016-05-10T15:10:36Z","body":"@orthoxerox \r\n\r\n> My proposal is about extension methods that are literally virtual and it requires no CLR changes.\r\n\r\n> However, the real purpose is extending classes from **other** assemblies with additional virtual methods, because typeswitch methods are maintenance hell.\r\n\r\nThose two statements are in conflict.  There is nothing in the CLR that would allow you to amend a type in a different assembly and add new virtual methods."}}