Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separating constructor and new? #193

Closed
domenic opened this issue Apr 15, 2020 · 3 comments · Fixed by #196
Closed

Separating constructor and new? #193

domenic opened this issue Apr 15, 2020 · 3 comments · Fixed by #196

Comments

@domenic
Copy link
Member

domenic commented Apr 15, 2020

I'm trying to implement whatwg/streams#1035 and running into the issue that we don't have a way to invoke the Web IDL new operation without also invoking the impl constructor.

The impl constructor is what backs the wrapper constructor. But in specs we have two different paths for creating platform objects:

  • new PlatformObject() from JS code runs these steps
  • Specs will do "new PlatformObject" and then initialize them directly.

We don't currently have a way of doing the latter.

I'll probably investigate with some patches locally in the streams repo, but this issue can track upstreaming them.

@domenic
Copy link
Member Author

domenic commented Apr 15, 2020

This is what I came up with. It does not require any impl-side changes.

exports.webidlNew = (globalObject, typeName, implModule) => {
  if (globalObject[utils.ctorRegistrySymbol] === undefined) {
    throw new Error('Internal error: invalid global object');
  }

  const ctor = globalObject[utils.ctorRegistrySymbol][typeName];
  if (ctor === undefined) {
    throw new Error(`Internal error: constructor ${typeName} is not installed on the passed global object`);
  }

  const obj = Object.create(ctor.prototype);
  Object.defineProperty(obj, utils.implSymbol, {
    value: Object.create(implModule.implementation.prototype),
    configurable: true
  });
  obj[utils.implSymbol][utils.wrapperSymbol] = obj;
  return obj[utils.implSymbol];
};

The arguments would change (to just globalObject, I think) if we exported this from the generated file. And we'd want to do some work to deduplicate the contents of this function with create/createImpl/setup. But it seems to work.

Naming it new is probably reasonable if it's an export, so that you'd use it as MyClass.new(globalObject). I named mine webidlNew because it's just in a utils file, and I wanted to be able to do const { webidlNew } = require("./utils.js").

@TimothyGu
Copy link
Member

How do you call the impl constructor after creating an object with webidlNew? Just wondering how this is useful.

@domenic
Copy link
Member Author

domenic commented Apr 16, 2020

domenic added a commit that referenced this issue Apr 17, 2020
domenic added a commit that referenced this issue Apr 17, 2020
domenic added a commit that referenced this issue Apr 17, 2020
domenic added a commit that referenced this issue Apr 17, 2020
Since I had to do some refactoring to reduce duplication anyway, this also includes general cleanup to the output, such as replacing obj with either value or wrapper, using arrow functions for our exports, and such. Closes #54.

Closes #193.
domenic added a commit that referenced this issue Apr 17, 2020
Since I had to do some refactoring to reduce duplication anyway, this also includes general cleanup to the output, such as replacing obj with either value or wrapper, using arrow functions for our exports, and such. Closes #54.

Closes #193.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants