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
Investigate using private fields in extHostTypes #91129
Comments
Yes! A little afraid of negative perf-impact when using |
Quick micro benchmark in Chrome: Native Private fields
function native(len) {
class F {
#a = 1;
#b = 2;
doSomething() {
return this.#a++ + this.#b++;
}
}
let out = 0
const f = new F();
for (let i = 0; i < len; ++i) {
out += f.doSomething();
}
return out;
}
console.time(); native(10000000); console.timeEnd(); Generated
function generated(len) {
class F {
#a = 1;
#b = 2;
doSomething() {
return this.#a++ + this.#b++;
}
}
let out = 0
const f = new F();
for (let i = 0; i < len; ++i) {
out += f.doSomething();
}
return out;
}
console.time(); native(10000000); console.timeEnd(); "use strict";
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
};
function generated(len) {
var _a, _b;
class F {
constructor() {
_a.set(this, 1);
_b.set(this, 2);
}
doSomething() {
var _c, _d;
return (__classPrivateFieldSet(this, _a, (_c = +__classPrivateFieldGet(this, _a)) + 1), _c) + (__classPrivateFieldSet(this, _b, (_d = +__classPrivateFieldGet(this, _b)) + 1), _d);
}
}
_a = new WeakMap(), _b = new WeakMap();
let out = 0;
const f = new F();
for (let i = 0; i < len; ++i) {
out += f.doSomething();
}
return out;
}
console.time();
native(10000000);
console.timeEnd(); So using private fields with weak maps does have some overhead. |
As a test, I converted
|
We have util that strips out the boilerplate preamble that TS emits before the actual code (see below) and we should teach it the private field get/set utils so that they don't get duplicated (when used in more files). Alternatively we emit the private field as-is - since our version of Electron supports this (we already have different targets in tsconfig.json and tsconfig.monaco.json)
|
We have to target |
It's a shame we don't have fine grained control over what is down-level compiled. I don't feel good to use target esnext because I don't know whats all in it but I would prefer to selectively target a feature like native privates... fyi - this where boiler plate removal happens: Line 337 in d729e50
|
I don't think we need a comprehensive push to adopt private properties and can instead handle this on a case by case basis I've adopted them on webviews since a few extensions were trying to access out existing |
Problem
Our APIs expose a few classes such as
WorkspaceEdit
orRange
to extensions. Some of these classes haveprivate
properties. However TypeScript's private keyword does not actual prevent extensions from accessing these fields. Extensions may mistakenly enumerate over these properties or mistakenly override these properties during subclassing if they are not careful! (although hopefully no one is subclassingWorkspaceEdit
:))Investigation
We should see if we can switch to use ECMAScript private fields for these properties instead. Private fields ensure the property is only visible within the class (and not to consumers of our API). While targeting ES6, private fields compile down to use
WeakMap
Not having truly private properties on these types is not a huge issue but I do think it is worth investigating a little since it is a best practice.
The text was updated successfully, but these errors were encountered: