{"action":"created","issue":{"url":"https://api.github.com/repos/jashkenas/coffeescript/issues/4354","repository_url":"https://api.github.com/repos/jashkenas/coffeescript","labels_url":"https://api.github.com/repos/jashkenas/coffeescript/issues/4354/labels{/name}","comments_url":"https://api.github.com/repos/jashkenas/coffeescript/issues/4354/comments","events_url":"https://api.github.com/repos/jashkenas/coffeescript/issues/4354/events","html_url":"https://github.com/jashkenas/coffeescript/pull/4354","id":187540908,"number":4354,"title":"[CS2] Compile class constructors to ES2015 classes","user":{"login":"connec","id":160652,"avatar_url":"https://avatars.githubusercontent.com/u/160652?v=3","gravatar_id":"","url":"https://api.github.com/users/connec","html_url":"https://github.com/connec","followers_url":"https://api.github.com/users/connec/followers","following_url":"https://api.github.com/users/connec/following{/other_user}","gists_url":"https://api.github.com/users/connec/gists{/gist_id}","starred_url":"https://api.github.com/users/connec/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/connec/subscriptions","organizations_url":"https://api.github.com/users/connec/orgs","repos_url":"https://api.github.com/users/connec/repos","events_url":"https://api.github.com/users/connec/events{/privacy}","received_events_url":"https://api.github.com/users/connec/received_events","type":"User","site_admin":false},"labels":[{"id":19132,"url":"https://api.github.com/repos/jashkenas/coffeescript/labels/change","name":"change","color":"178c3c","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":{"url":"https://api.github.com/repos/jashkenas/coffeescript/milestones/10","html_url":"https://github.com/jashkenas/coffeescript/milestone/10","labels_url":"https://api.github.com/repos/jashkenas/coffeescript/milestones/10/labels","id":2015479,"number":10,"title":"2.0.0","description":"A breaking-change release of CoffeeScript that outputs the latest implemented ECMAScript syntax whenever possible.","creator":{"login":"GeoffreyBooth","id":456802,"avatar_url":"https://avatars.githubusercontent.com/u/456802?v=3","gravatar_id":"","url":"https://api.github.com/users/GeoffreyBooth","html_url":"https://github.com/GeoffreyBooth","followers_url":"https://api.github.com/users/GeoffreyBooth/followers","following_url":"https://api.github.com/users/GeoffreyBooth/following{/other_user}","gists_url":"https://api.github.com/users/GeoffreyBooth/gists{/gist_id}","starred_url":"https://api.github.com/users/GeoffreyBooth/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GeoffreyBooth/subscriptions","organizations_url":"https://api.github.com/users/GeoffreyBooth/orgs","repos_url":"https://api.github.com/users/GeoffreyBooth/repos","events_url":"https://api.github.com/users/GeoffreyBooth/events{/privacy}","received_events_url":"https://api.github.com/users/GeoffreyBooth/received_events","type":"User","site_admin":false},"open_issues":1,"closed_issues":7,"state":"open","created_at":"2016-09-20T04:18:33Z","updated_at":"2016-12-03T19:41:25Z","due_on":null,"closed_at":null},"comments":93,"created_at":"2016-11-06T04:15:22Z","updated_at":"2016-12-29T12:00:26Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/jashkenas/coffeescript/pulls/4354","html_url":"https://github.com/jashkenas/coffeescript/pull/4354","diff_url":"https://github.com/jashkenas/coffeescript/pull/4354.diff","patch_url":"https://github.com/jashkenas/coffeescript/pull/4354.patch"},"body":"OK, I've pushed what I believe is a more-or-less \"ready\" version of classes. I've adopted a similar approach to the previous PR, whereby valid methods are hoisted into an ES2015 class declaration, and other expressions are left as-is. I've also made it so that classes are compiled \"bare\", without an enclosing IIFE, where possible.\r\n\r\nI've standardised the hoisting thing a little bit. `hoist` is now a method on `Base`, meaning any node can be hoisted. Calling `hoist` mutates the source node and returns a new target node, which should be put in the tree at the desired output location. When the target is compiled, it returns a fragments placeholder. When the source is compiled, it updates the target's fragments. Finally, `Block#compileRoot` will expand all placeholder fragments before returning the result.\r\n\r\nI've not touched `super` outside constructors as that adds quite a bit of surface area and would be better handled separately, imo. The downside of this is that, for now, derived classes always need an enclosing IIFE. Handling `super` is something I'd be happy to look at as a subsequent PR, unless someone else wants to tackle it.\r\n\r\nThere is one remaining annoyance, which is the assignment. This is needed to allow `Literal` to be referenced in the second example below (and throughout the CS source). We could remove this, which would mean that classes created in expressions can only be referenced by the result of the expression (e.g. `exports.Foo = class Foo` could only be referenced as `exports.Foo`). I've erred on the side of compatibility for now, as it's easy to take this out later if we so choose.\r\n\r\nI've not added any test, the following would be good to have. Any test contributions would be great.\r\n\r\n- `@` params with/without `super`, including errors\r\n- bound functions with/without `super`, including errors\r\n- `super` in arrow functions in constructors\r\n- `super` and external constructors\r\n- ... any more anyone can think of\r\n\r\nAs a final note, the diff looks fairly large as I ended up rewriting the `Class` node, however a lot of the logic hasn't changed, its just been moved around to better line-up with the new usage of the node. I felt this was better than continuing to stretch the previous `Class` out of shape. Apologies to reviewers.\r\n\r\n<table>\r\n<tr>\r\n<td valign='top'>\r\n<pre lang='coffee'>\r\nclass Polygon\r\n  constructor: (@height, @width) ->\r\n<br>\r\n  area: ->\r\n    @calcArea()\r\n<br>\r\n  calcArea: ->\r\n    @height * @width\r\n</pre>\r\n</td>\r\n<td>\r\n<pre lang='js'>\r\nvar Polygon;\r\n<br>\r\nPolygon = class Polygon {\r\n  constructor(height, width) {\r\n    this.height = height;\r\n    this.width = width;\r\n  }\r\n<br>\r\n  area() {\r\n    return this.calcArea();\r\n  }\r\n<br>\r\n  calcArea() {\r\n    return this.height * this.width;\r\n  }\r\n<br>\r\n};\r\n</pre>\r\n</td>\r\n</tr>\r\n<tr>\r\n<td valign='top'><pre lang='coffee'>\r\nexports.Literal = class Literal extends Base\r\n  constructor: (@value) ->\r\n<br>\r\n  compileNode: (o) ->\r\n    super\r\n</pre></td>\r\n<td><pre lang='js'>\r\nvar Literal;\r\n<br>\r\nexports.Literal = Literal = (function(superClass) {\r\n  class Literal extends superClass {\r\n    constructor(value) {\r\n      super(...arguments);\r\n      this.value = value;\r\n    }\r\n<br>\r\n    compileNode(o) {\r\n      return Literal.__super__.compileNode.call(this, ...arguments);\r\n    }\r\n<br>\r\n  };\r\n<br>\r\n  Literal.__super__ = superClass.prototype;\r\n<br>\r\n  return Literal;\r\n<br>\r\n})(Base);\r\n</pre></td>\r\n</tr>\r\n<tr>\r\n<td valign='top'><pre lang='coffee'>\r\nclass Animal\r\n  constructor: (@name) ->\r\n<br>\r\n  move: (meters) ->\r\n    alert @name + \" moved #{meters}m.\"\r\n<br>\r\nclass Snake extends Animal\r\n  move: ->\r\n    alert \"Slithering...\"\r\n    super 5\r\n<br>\r\nclass Horse extends Animal\r\n  move: ->\r\n    alert \"Galloping...\"\r\n    super 45\r\n<br>\r\nsam = new Snake \"Sammy the Python\"\r\ntom = new Horse \"Tommy the Palomino\"\r\n<br>\r\nsam.move()\r\ntom.move()\r\n</pre></td>\r\n<td><pre lang='js'>\r\n// Generated by CoffeeScript 2.0.0-alpha\r\nvar Animal, Horse, Snake, sam, tom;\r\n<br>\r\nAnimal = class Animal {\r\n  constructor(name) {\r\n    this.name = name;\r\n  }\r\n<br>\r\n  move(meters) {\r\n    return alert(this.name + (\" moved \" + meters + \"m.\"));\r\n  }\r\n<br>\r\n};\r\n<br>\r\nSnake = (function(superClass) {\r\n  class Snake extends superClass {\r\n    move() {\r\n      alert(\"Slithering...\");\r\n      return Snake.__super__.move.call(this, 5);\r\n    }\r\n<br>\r\n  };\r\n<br>\r\n  Snake.__super__ = superClass.prototype;\r\n<br>\r\n  return Snake;\r\n<br>\r\n})(Animal);\r\n<br>\r\nHorse = (function(superClass) {\r\n  class Horse extends superClass {\r\n    move() {\r\n      alert(\"Galloping...\");\r\n      return Horse.__super__.move.call(this, 45);\r\n    }\r\n<br>\r\n  };\r\n<br>\r\n  Horse.__super__ = superClass.prototype;\r\n<br>\r\n  return Horse;\r\n<br>\r\n})(Animal);\r\n<br>\r\nsam = new Snake(\"Sammy the Python\");\r\n<br>\r\ntom = new Horse(\"Tommy the Palomino\");\r\n<br>\r\nsam.move();\r\n<br>\r\ntom.move();\r\n</pre></td>\r\n</tr>\r\n</table>\r\n\r\nSupersedes #4330."},"comment":{"url":"https://api.github.com/repos/jashkenas/coffeescript/issues/comments/269620641","html_url":"https://github.com/jashkenas/coffeescript/pull/4354#issuecomment-269620641","issue_url":"https://api.github.com/repos/jashkenas/coffeescript/issues/4354","id":269620641,"user":{"login":"svicalifornia","id":134837,"avatar_url":"https://avatars.githubusercontent.com/u/134837?v=3","gravatar_id":"","url":"https://api.github.com/users/svicalifornia","html_url":"https://github.com/svicalifornia","followers_url":"https://api.github.com/users/svicalifornia/followers","following_url":"https://api.github.com/users/svicalifornia/following{/other_user}","gists_url":"https://api.github.com/users/svicalifornia/gists{/gist_id}","starred_url":"https://api.github.com/users/svicalifornia/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/svicalifornia/subscriptions","organizations_url":"https://api.github.com/users/svicalifornia/orgs","repos_url":"https://api.github.com/users/svicalifornia/repos","events_url":"https://api.github.com/users/svicalifornia/events{/privacy}","received_events_url":"https://api.github.com/users/svicalifornia/received_events","type":"User","site_admin":false},"created_at":"2016-12-29T12:00:26Z","updated_at":"2016-12-29T12:00:26Z","body":"@connec More concerns about `super`:\r\n\r\n1. Is it possible in ES2015 to call `super` more than once from the same function?\r\n2. If so, is it possible to call `super` more than once from a `for` or `while` loop?\r\n3. If so, how would we ensure that `@params` are set on `this` only on the first iteration of such a loop?"}}
{"actor":{"display_login":"svicalifornia"}}