{"action":"created","issue":{"url":"https://api.github.com/repos/ponylang/ponyc/issues/683","repository_url":"https://api.github.com/repos/ponylang/ponyc","labels_url":"https://api.github.com/repos/ponylang/ponyc/issues/683/labels{/name}","comments_url":"https://api.github.com/repos/ponylang/ponyc/issues/683/comments","events_url":"https://api.github.com/repos/ponylang/ponyc/issues/683/events","html_url":"https://github.com/ponylang/ponyc/issues/683","id":145446593,"number":683,"title":"Functions with constraints on type parameters of containing type.","user":{"login":"jemc","id":4623870,"avatar_url":"https://avatars.githubusercontent.com/u/4623870?v=3","gravatar_id":"","url":"https://api.github.com/users/jemc","html_url":"https://github.com/jemc","followers_url":"https://api.github.com/users/jemc/followers","following_url":"https://api.github.com/users/jemc/following{/other_user}","gists_url":"https://api.github.com/users/jemc/gists{/gist_id}","starred_url":"https://api.github.com/users/jemc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jemc/subscriptions","organizations_url":"https://api.github.com/users/jemc/orgs","repos_url":"https://api.github.com/users/jemc/repos","events_url":"https://api.github.com/users/jemc/events{/privacy}","received_events_url":"https://api.github.com/users/jemc/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/ponylang/ponyc/labels/enhancement","name":"enhancement","color":"84b6eb"},{"url":"https://api.github.com/repos/ponylang/ponyc/labels/hard","name":"hard","color":"000000"}],"state":"open","locked":false,"assignee":{"login":"sylvanc","id":2785007,"avatar_url":"https://avatars.githubusercontent.com/u/2785007?v=3","gravatar_id":"","url":"https://api.github.com/users/sylvanc","html_url":"https://github.com/sylvanc","followers_url":"https://api.github.com/users/sylvanc/followers","following_url":"https://api.github.com/users/sylvanc/following{/other_user}","gists_url":"https://api.github.com/users/sylvanc/gists{/gist_id}","starred_url":"https://api.github.com/users/sylvanc/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sylvanc/subscriptions","organizations_url":"https://api.github.com/users/sylvanc/orgs","repos_url":"https://api.github.com/users/sylvanc/repos","events_url":"https://api.github.com/users/sylvanc/events{/privacy}","received_events_url":"https://api.github.com/users/sylvanc/received_events","type":"User","site_admin":false},"milestone":null,"comments":2,"created_at":"2016-04-03T02:44:10Z","updated_at":"2016-04-04T20:36:48Z","closed_at":null,"body":"We currently have type parameters on types (`class`, `actor`, etc), which allow passing in type parameters when referring to that type (for example, `Array[String]`).  We also have type parameters on functions, which allow passing in type parameters when calling the function (for example, `h.assert_equal[String](\"foo\", \"foo\")`).  Both of these involve the compiler generating separate LLVM functions for each type combination encountered at call sites.\r\n\r\nType parameters can also be constrained.  For example, `h.assert_equal` constrains its type parameter so that the given type must be both `Equatable` for checking equality, and `Stringable` for printing.  If the given type doesn't meet the constraints, it will generate a compiler error.\r\n\r\nWhen working on generics, I've often wished for another related feature: making the function conditional on type parameters of the containing type.\r\n\r\nFor example, we don't have an `Array.string` function because not everything you might want to put in an `Array` is `Stringable` - that is, we might be able to implement `Array[U8].string()` or `Array[String].string()`, but we can't implement `Array[MyClass]` if `MyClass` is not `Stringable`.  Currently, to accomplish this we would need to do one of two things:\r\n\r\n1. Constrain `class Array[A]` to `class Array[A: Stringable]`.  However, this would mean we could no longer even create an `Array[MyClass]` if `MyClass` is not `Stringable`.  So this doesn't really work for us.\r\n2. Make the `Array.string()` method do a type conversion with `as`, and `error` if the type `A` is not `Stringable`.  However, this is still a bit silly - our compiler can know at compile time whether `A` is `Stringable`, so why defer this to runtime?  Why even allow us to call `Array[MyClass].string()` if it will never work, and why make us surround `Array[String].string()` with a `try ... end` block if it will *always* work?\r\n\r\nMy proposal would be:\r\n\r\nAllow functions that will compile only when additional constraints on the outer type is met.  For example, when compiling `Array[A]`, the `string` method would be just ignored and left out if `A` was not `Stringable`.\r\n\r\nI'm open to ideas about syntax, but my current thought is this - since we already can't shadow a type parameter name (for example, inside `class Array[A]` we cannot currently define `fun string[A]()`), we can do this by \"overloading\" the existing constraint syntax, referencing the outer existing type parameter name, and constraining it further (for example, inside `class Array[A]` we might define `fun string[A: Stringable]()`)."},"comment":{"url":"https://api.github.com/repos/ponylang/ponyc/issues/comments/205483014","html_url":"https://github.com/ponylang/ponyc/issues/683#issuecomment-205483014","issue_url":"https://api.github.com/repos/ponylang/ponyc/issues/683","id":205483014,"user":{"login":"tmmcguire","id":1326568,"avatar_url":"https://avatars.githubusercontent.com/u/1326568?v=3","gravatar_id":"","url":"https://api.github.com/users/tmmcguire","html_url":"https://github.com/tmmcguire","followers_url":"https://api.github.com/users/tmmcguire/followers","following_url":"https://api.github.com/users/tmmcguire/following{/other_user}","gists_url":"https://api.github.com/users/tmmcguire/gists{/gist_id}","starred_url":"https://api.github.com/users/tmmcguire/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tmmcguire/subscriptions","organizations_url":"https://api.github.com/users/tmmcguire/orgs","repos_url":"https://api.github.com/users/tmmcguire/repos","events_url":"https://api.github.com/users/tmmcguire/events{/privacy}","received_events_url":"https://api.github.com/users/tmmcguire/received_events","type":"User","site_admin":false},"created_at":"2016-04-04T20:36:48Z","updated_at":"2016-04-04T20:36:48Z","body":"Is this anything like the `List.contains` (https://github.com/ponylang/ponyc/blob/master/packages/collections/list.pony#L491-L499) type parameters (which I've been unable to duplicate for an array element comparison lambda), \r\n```pony\r\nfun contains[B: (A & HasEq[A!] #read) = A](a: box->B): Bool =>\r\n    \"\"\"\r\n    Returns true if the list contains the provided element, false otherwise.\r\n    \"\"\"\r\n    try\r\n      _contains[B](head(), a)\r\n    else\r\n      false\r\n    end\r\n```"}}