{"action":"created","issue":{"url":"https://api.github.com/repos/Kotlin/KEEP/issues/87","repository_url":"https://api.github.com/repos/Kotlin/KEEP","labels_url":"https://api.github.com/repos/Kotlin/KEEP/issues/87/labels{/name}","comments_url":"https://api.github.com/repos/Kotlin/KEEP/issues/87/comments","events_url":"https://api.github.com/repos/Kotlin/KEEP/issues/87/events","html_url":"https://github.com/Kotlin/KEEP/pull/87","id":262200015,"number":87,"title":"Type Classes as extensions in Kotlin","user":{"login":"raulraja","id":456796,"avatar_url":"https://avatars3.githubusercontent.com/u/456796?v=4","gravatar_id":"","url":"https://api.github.com/users/raulraja","html_url":"https://github.com/raulraja","followers_url":"https://api.github.com/users/raulraja/followers","following_url":"https://api.github.com/users/raulraja/following{/other_user}","gists_url":"https://api.github.com/users/raulraja/gists{/gist_id}","starred_url":"https://api.github.com/users/raulraja/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/raulraja/subscriptions","organizations_url":"https://api.github.com/users/raulraja/orgs","repos_url":"https://api.github.com/users/raulraja/repos","events_url":"https://api.github.com/users/raulraja/events{/privacy}","received_events_url":"https://api.github.com/users/raulraja/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":18,"created_at":"2017-10-02T19:31:38Z","updated_at":"2017-10-05T07:01:46Z","closed_at":null,"author_association":"NONE","pull_request":{"url":"https://api.github.com/repos/Kotlin/KEEP/pulls/87","html_url":"https://github.com/Kotlin/KEEP/pull/87","diff_url":"https://github.com/Kotlin/KEEP/pull/87.diff","patch_url":"https://github.com/Kotlin/KEEP/pull/87.patch"},"body":"The following PR adds a KEEP proposing a natural fit for Type Classes and higher kinded types in the Kotlin's extensions mechanism."},"comment":{"url":"https://api.github.com/repos/Kotlin/KEEP/issues/comments/334376795","html_url":"https://github.com/Kotlin/KEEP/pull/87#issuecomment-334376795","issue_url":"https://api.github.com/repos/Kotlin/KEEP/issues/87","id":334376795,"user":{"login":"dnpetrov","id":544563,"avatar_url":"https://avatars3.githubusercontent.com/u/544563?v=4","gravatar_id":"","url":"https://api.github.com/users/dnpetrov","html_url":"https://github.com/dnpetrov","followers_url":"https://api.github.com/users/dnpetrov/followers","following_url":"https://api.github.com/users/dnpetrov/following{/other_user}","gists_url":"https://api.github.com/users/dnpetrov/gists{/gist_id}","starred_url":"https://api.github.com/users/dnpetrov/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dnpetrov/subscriptions","organizations_url":"https://api.github.com/users/dnpetrov/orgs","repos_url":"https://api.github.com/users/dnpetrov/repos","events_url":"https://api.github.com/users/dnpetrov/events{/privacy}","received_events_url":"https://api.github.com/users/dnpetrov/received_events","type":"User","site_admin":false},"created_at":"2017-10-05T07:01:46Z","updated_at":"2017-10-05T07:01:46Z","author_association":"CONTRIBUTOR","body":"@elizarov \r\n> However, as soon as you allow applying this syntax to multiple types, the story with \"standalone\" (static? but not really) functions like empty becomes complicated. We do want those functions to extend \"the type\" and we want them being applicable on the type itself (like companion object functions for the type). You should be able to use Int.empty() expression in the context of Monoid<Int>, but with multiple types it becomes unclear which type is being extended this way.\r\n\r\nThis approach has some issues with overloading. E.g., what if I have several different type classes (extension interfaces, whatever) for `T` with method `empty()`?\r\nI'd suppose it should rather be more explicit, like in https://github.com/Kotlin/KEEP/pull/87#issuecomment-334096622, where type class implementation is passes as a named parameter, which has special default value resolution strategy.\r\n\r\nI'd expect something like:\r\n```\r\nextension interface Monoid<T> {\r\n    fun T.combine(b: T): T\r\n    fun empty(): T\r\n}\r\n\r\nextension object AdditiveInt : Monoid<Int> {\r\n    override fun Int.combine(b: Int): Int = this + b\r\n    override fun empty(): Int = 0\r\n}\r\n\r\nextension object StringConcatenation : Monoid<String> {\r\n    override fun String.combine(b: String): String = this + b\r\n    override fun empty(): String = \"\"\r\n}\r\n\r\nfun <T> T.timesN(n: Int, extension monoid: Monoid<T>): T {\r\n    var result = empty() // 'monoid' is an implicit dispatch receiver\r\n    for (i in 0 until n) {\r\n        result = result.combine(this) // 'monoid' is an implicit dispatch receiver, 'combine' is a member extension\r\n    }\r\n    return result\r\n}\r\n\r\nfun test() {\r\n    assertEquals(\"abcabcabcabc\", \"abc\".timesN(4))\r\n}\r\n```"}}
{"actor":{"display_login":"dnpetrov"}}