{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/1061","repository_url":"https://api.github.com/repos/dotnet/csharplang","labels_url":"https://api.github.com/repos/dotnet/csharplang/issues/1061/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/csharplang/issues/1061/comments","events_url":"https://api.github.com/repos/dotnet/csharplang/issues/1061/events","html_url":"https://github.com/dotnet/csharplang/issues/1061","id":269895508,"number":1061,"title":"Proposal: Virtual Extension Methods","user":{"login":"dmitriyse","id":10322215,"avatar_url":"https://avatars3.githubusercontent.com/u/10322215?v=4","gravatar_id":"","url":"https://api.github.com/users/dmitriyse","html_url":"https://github.com/dmitriyse","followers_url":"https://api.github.com/users/dmitriyse/followers","following_url":"https://api.github.com/users/dmitriyse/following{/other_user}","gists_url":"https://api.github.com/users/dmitriyse/gists{/gist_id}","starred_url":"https://api.github.com/users/dmitriyse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dmitriyse/subscriptions","organizations_url":"https://api.github.com/users/dmitriyse/orgs","repos_url":"https://api.github.com/users/dmitriyse/repos","events_url":"https://api.github.com/users/dmitriyse/events{/privacy}","received_events_url":"https://api.github.com/users/dmitriyse/received_events","type":"User","site_admin":false},"labels":[{"id":537024200,"url":"https://api.github.com/repos/dotnet/csharplang/labels/Discussion","name":"Discussion","color":"c2e0c6","default":false},{"id":545773793,"url":"https://api.github.com/repos/dotnet/csharplang/labels/Feature%20Request","name":"Feature Request","color":"d4c5f9","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":15,"created_at":"2017-10-31T09:48:03Z","updated_at":"2018-03-18T03:27:17Z","closed_at":null,"author_association":"NONE","body":"This proposal adds to C# an ability to define virtual extension methods and override them.\r\nPrimary benefit of this proposal is ability to build advanced extensible Linq-like frameworks.\r\nAnd even binary-compatible upgrade of existing Linq-like frameworks with extensibility features.\r\n\r\nNew syntax usage example:\r\n\r\n```csharp\r\n// We even can upgrade linq with binary compatiblity\r\npublic static class Enumerable\r\n{\r\n    // ...\r\n\r\n    public static virtual int Count<T>(this IEnumerable<T> items)\r\n    {\r\n        // for binary compatibility here should be original Linq code with some sort of type checks.\r\n\r\n        int count = 0;\r\n        foreach (var i in items)\r\n        {\r\n            count++;\r\n        }\r\n        return count;     \r\n    }\r\n\r\n    // ...\r\n}\r\n\r\npublic class SmartList<T>: IEnumerable<T>\r\n{\r\n    private int m_count;\r\n    \r\n    // ...\r\n\r\n    // Custom implementation of \"int Enumerable.Count<T>(this IEnumerable<T>)\"\r\n    override int Enumerable.Count<T>()\r\n    {\r\n        return m_count;\r\n    }\r\n\r\n    // ...\r\n}\r\n```\r\nC# 8.0+ will translate above example to this code (assuming that #52 already in the language):\r\n(That's what CLR will see)\r\n\r\n```CSharp\r\npublic static class Enumerable\r\n{\r\n     public static int Count<T>(IEnumerable<T> items)\r\n     {\r\n         // -----  Compiler generated -----\r\n         if (items is Enumerable.__IExtension__Count<T> itemsEx)\r\n         {\r\n              return itemsEx.Count();\r\n         }\r\n         // -----------------------------------\r\n\r\n         int count = 0;\r\n         foreach (var i in items)\r\n         {\r\n             count++;\r\n         }\r\n         return count;     \r\n     }\r\n     \r\n     public interface __IExtension__Count<T>: IEnumerable<T>\r\n     {\r\n         int Count()\r\n         {\r\n             // Body from Enumerable.Count but with small transformation.\r\n             int count = 0;\r\n             foreach (var i in this) // items variable is replaced by !this!\r\n             {\r\n                 count++;\r\n             }\r\n             return count;     \r\n         }\r\n     }\r\n}\r\n\r\npublic class SmartList<T>: IEnumerable<T>, Enumerable.__IExtension__Count<T>\r\n{\r\n    private int m_count;\r\n\r\n    // ...\r\n\r\n    int Enumerable.__IExtension__Count<T>()\r\n    {\r\n        return m_count;\r\n    }\r\n\r\n   // ...\r\n\r\n}\r\n```\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/csharplang/issues/comments/373970089","html_url":"https://github.com/dotnet/csharplang/issues/1061#issuecomment-373970089","issue_url":"https://api.github.com/repos/dotnet/csharplang/issues/1061","id":373970089,"user":{"login":"Xenoprimate","id":27736510,"avatar_url":"https://avatars1.githubusercontent.com/u/27736510?v=4","gravatar_id":"","url":"https://api.github.com/users/Xenoprimate","html_url":"https://github.com/Xenoprimate","followers_url":"https://api.github.com/users/Xenoprimate/followers","following_url":"https://api.github.com/users/Xenoprimate/following{/other_user}","gists_url":"https://api.github.com/users/Xenoprimate/gists{/gist_id}","starred_url":"https://api.github.com/users/Xenoprimate/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Xenoprimate/subscriptions","organizations_url":"https://api.github.com/users/Xenoprimate/orgs","repos_url":"https://api.github.com/users/Xenoprimate/repos","events_url":"https://api.github.com/users/Xenoprimate/events{/privacy}","received_events_url":"https://api.github.com/users/Xenoprimate/received_events","type":"User","site_admin":false},"created_at":"2018-03-18T03:27:17Z","updated_at":"2018-03-18T03:27:17Z","author_association":"NONE","body":"In the original proposal, one of the motivations given for this feature mentions that adding default interface implementations \"provides the elements of the traits language feature\".\r\n\r\nAs it stands, I don't see how this proposal adds anything to the language wrt the 'traits' feature that we can't already acheive with other workarounds; mostly because you're not inheriting default methods.\r\n\r\nI can already write something like this:\r\n\r\n```csharp\r\npublic interface IMyTrait {\r\n\tvoid SomeMethod();\r\n}\r\n\r\npublic static class MyTraitDefaultImplProvider {\r\n\tpublic static void SomeMethod(IMyTrait @this) {\r\n\t\tConsole.WriteLine($\"Caller: {@this}\");\r\n\t}\r\n}\r\n\r\npublic class TraitImplementingClass : IMyTrait {\r\n\tpublic void SomeMethod() => MyTraitDefaultImplProvider.SomeMethod(this);\r\n}\r\n```\r\n\r\nThe proposed net result of being able to replace `MyTraitDefaultImplProvider.SomeMethod(this)` with `IMyTrait.base.SomeMethod()` from this context is not really any kind of useful addition, in my opinion. The only small boon I see is that default implementations are defined in the interface itself rather than in a 'friend' static class.\r\n\r\nI actually really want traits in C# (in fact I'd even push for full mixins/MI, but that's for another discussion). However I feel like using this feature as it stands is not meaningfully useful (in the context of supporting traits). Furthermore, it just seems to be distracting from the debate around the other motivations.\r\n\r\nApologies if I'm repeating something already said or accidentally ignoring a rebuttal that's already been posted. There's a lot of comments on this page already."}}
{"actor":{"display_login":"Xenoprimate"}}