{"action":"created","issue":{"url":"https://api.github.com/repos/babel/babel/issues/4480","repository_url":"https://api.github.com/repos/babel/babel","labels_url":"https://api.github.com/repos/babel/babel/issues/4480/labels{/name}","comments_url":"https://api.github.com/repos/babel/babel/issues/4480/comments","events_url":"https://api.github.com/repos/babel/babel/issues/4480/events","html_url":"https://github.com/babel/babel/issues/4480","id":175750992,"number":4480,"title":"Native extends breaks HTMLELement, Array, and others","user":{"login":"WebReflection","id":85749,"avatar_url":"https://avatars.githubusercontent.com/u/85749?v=3","gravatar_id":"","url":"https://api.github.com/users/WebReflection","html_url":"https://github.com/WebReflection","followers_url":"https://api.github.com/users/WebReflection/followers","following_url":"https://api.github.com/users/WebReflection/following{/other_user}","gists_url":"https://api.github.com/users/WebReflection/gists{/gist_id}","starred_url":"https://api.github.com/users/WebReflection/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebReflection/subscriptions","organizations_url":"https://api.github.com/users/WebReflection/orgs","repos_url":"https://api.github.com/users/WebReflection/repos","events_url":"https://api.github.com/users/WebReflection/events{/privacy}","received_events_url":"https://api.github.com/users/WebReflection/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":11,"created_at":"2016-09-08T13:17:00Z","updated_at":"2016-10-18T09:32:53Z","closed_at":null,"body":"Current Babel transform, when it comes to call the parent\r\n```js\r\nfunction _possibleConstructorReturn(self, call) {\r\n  if (!self) {\r\n    throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\r\n  }\r\n  return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self;\r\n}\r\n```\r\nIt's a way too poor implementation.\r\n\r\nIf we take the current basic ES6 compat syntax:\r\n```js\r\nclass List extends Array {}\r\n```\r\nWe'll realize babel does a bad job.\r\n```js\r\nvar l = new List();\r\nl instanceof List; // false\r\n```\r\nThe reason is simple: Babel replace the returns and exit, without caring about userland expectations.\r\n\r\nThis is how above basic extend should desugar:\r\n```js\r\nfunction List() {\r\n  return Object.setPrototypeOf(\r\n    Array.apply(this, arguments),\r\n    List.prototype\r\n  );\r\n}\r\n```\r\n\r\nIt's a very ad-hoc case for the initial example that currently fails, but it's good enough to understand that inheriting the prototype is the least of the problem.\r\n\r\nIndeed, we have 3 ways to do that within a transpiled code:\r\n```js\r\n// losing the initial prototype\r\n// for polyfilled ES5+ or lower\r\nList.prototype = Object.create(\r\n  Array.prototype,\r\n  {constructor: {\r\n    configurable: true,\r\n    writable: true,\r\n    value: List.prototype\r\n  }}\r\n);\r\n\r\n// using a cleaner way\r\n// for ES5+ compliant targets\r\nObject.setPrototypeOf(\r\n  List.prototype,\r\n  Array.prototype\r\n);\r\n\r\n// using a cleaner way\r\n// that works well with\r\n// partially polyfilled .setPrototypeOf\r\nList.prototype = Object.setPrototypeOf(\r\n  List.prototype,\r\n  Array.prototype\r\n);\r\n```\r\n\r\nSolved the inheritance bit, considering Babel also set the prototype of each constructor,\r\nwe need to address cases where a `super` call might \"_upgrade_\" the current context, like it is for `HTMLELement` or exotic native objects.\r\n\r\n```js\r\n// native ES6 static example\r\nclass List extends Array {\r\n  constructor(a, b, c) {\r\n    super(a, b);\r\n    this.push(c);\r\n  }\r\n}\r\n```\r\nAbove case should desugar to something like the follwoing:\r\n```js\r\nfunction List(a, b, c) {\r\n  // the super bit\r\n  var self = Object.setPrototypeOf(\r\n    Array.call(this, a, b),\r\n    List.prototype\r\n  );\r\n  // the rest with swapped context\r\n  self.push(c);\r\n  // at the end\r\n  return self;\r\n}\r\n```\r\nwhich is also ad-hoc example code for the previous example.\r\n\r\nConsidering a transpiler will get the arguments part easily right, this is how previous case could be generically transpiled for arguments used in both constructors:\r\n```js\r\n// to make it as generic as possible\r\nfunction Child() {\r\n\r\n  // the super call bit desugar to ...\r\n  var\r\n    instance = Object.getPrototypeOf(Child)\r\n        .apply(this, arguments),\r\n    type = instance ? typeof instance : '',\r\n    // if Parent overwrote its default return\r\n    self = (type === 'object' || type === 'function') ?\r\n      // upgrade the instance to reflect Child constructor\r\n      Object.setPrototypeOf(instance, Child.prototype) :\r\n      // otherwise use the current context as is\r\n      this\r\n  ;\r\n\r\n  // at this point, the rest of the constructor\r\n  // should use `self` instead of `this`\r\n  self.push(c);\r\n\r\n  // and return `self` reference at the end\r\n  return self;\r\n}\r\n```\r\n\r\nThe last problem is that modern syntax would use [Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect) to create any sort of object, instead of old, ES3 friendly, `.call` or `.apply` way.\r\n\r\nFollowing a past, present, and even future proof approach:\r\n```js\r\nvar\r\n  reConstruct = typeof Reflect === 'object' ?\r\n    Reflect.construct :\r\n    function (Parent, args, Child) {\r\n      return Parent.apply(this, args);\r\n    }\r\n;\r\n\r\nfunction Child() {\r\n\r\n  // the super call bit\r\n  var\r\n    instance = reConstruct.call(\r\n      this,\r\n      Object.getPrototypeOf(Child),\r\n      arguments,\r\n      Child\r\n    ),\r\n    type = instance ? typeof instance : '',\r\n    self = (type === 'object' || type === 'function') ?\r\n      Object.setPrototypeOf(instance, Child.prototype) :\r\n      this\r\n  ;\r\n\r\n  // the rest of the constructor body\r\n  self.push(c);\r\n\r\n  // at the end or instead of empty returns\r\n  return self;\r\n}\r\n```\r\n\r\nAbove solution would work with userland, exotic, or DOM constructors, and in both native and transpiled engines."},"comment":{"url":"https://api.github.com/repos/babel/babel/issues/comments/254456197","html_url":"https://github.com/babel/babel/issues/4480#issuecomment-254456197","issue_url":"https://api.github.com/repos/babel/babel/issues/4480","id":254456197,"user":{"login":"WebReflection","id":85749,"avatar_url":"https://avatars.githubusercontent.com/u/85749?v=3","gravatar_id":"","url":"https://api.github.com/users/WebReflection","html_url":"https://github.com/WebReflection","followers_url":"https://api.github.com/users/WebReflection/followers","following_url":"https://api.github.com/users/WebReflection/following{/other_user}","gists_url":"https://api.github.com/users/WebReflection/gists{/gist_id}","starred_url":"https://api.github.com/users/WebReflection/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebReflection/subscriptions","organizations_url":"https://api.github.com/users/WebReflection/orgs","repos_url":"https://api.github.com/users/WebReflection/repos","events_url":"https://api.github.com/users/WebReflection/events{/privacy}","received_events_url":"https://api.github.com/users/WebReflection/received_events","type":"User","site_admin":false},"created_at":"2016-10-18T09:32:53Z","updated_at":"2016-10-18T09:32:53Z","body":"It looks like we all agree on this point: https://github.com/w3c/webcomponents/issues/587#issuecomment-254348659\r\n\r\nNot even browser vendors developers can workaround the current broken state when it comes to `super`.\r\n\r\nI won't have time soon to solve this issue, I'd like to understand if it has any priority though so at least I can better reply to people asking me why my polyfill is broken ( when the issue is them using Babel :-( )\r\n\r\nThanks for any sort of ETA / outcome"}}
{"actor":{"display_login":"WebReflection"}}