-
Notifications
You must be signed in to change notification settings - Fork 30k
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
tools: add prefer-proto
rule
#46083
tools: add prefer-proto
rule
#46083
Conversation
fixup: add support for `Object.create(null)` fixup: extend to any 1-argument Object.create call fixup: add tests
Review requested:
|
cc @aduh95 |
I'm in favor of having more consistency here. I have a couple of questions:
|
The alternative form of I am more than happy to do a more thorough audit once there's general agreement on the lint rule's philosophy (prefer syntax over API) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but I'm probably less opinionated about this than some other folks 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 with the change suggested in https://github.com/nodejs/node/pull/46083/files#r1060980774
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm when the tests succeed
eb9100e
to
06b629e
Compare
fixup: add support for `Object.create(null)` fixup: extend to any 1-argument Object.create call fixup: add tests PR-URL: nodejs#46083 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
@ljharb This commit didn't land cleanly on v19.x because some branches contain the |
fixup: add support for `Object.create(null)` fixup: extend to any 1-argument Object.create call fixup: add tests PR-URL: nodejs#46083 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Is there some explanation for why this change happened? Nothing against it, just could use some explanation in the PR description so people know why we prefer the syntax form over the function call form. |
@Qard sure, i'd phrase it as:
Does that suffice? |
Sounds reasonable, thanks! 🙂 |
fixup: add support for `Object.create(null)` fixup: extend to any 1-argument Object.create call fixup: add tests PR-URL: #46083 Backport-PR-URL: #46239 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Geoffrey Booth <webadmin@geoffreybooth.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Mohammed Keyvanzadeh <mohammadkeyvanzade94@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com> Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
@ljharb about this:
I have very mixed results across gjs, bun, or node ... not the best benchmark ever, but Here a test example: const {assign, create, setPrototypeOf} = Object;
class Test {
constructor(i) {
this.i = i;
}
}
class CEWValue {
constructor(value) {
this.value = value;
}
get configurable() { return true }
get enumerable() { return true }
get writable() { return true }
}
class Null {}
setPrototypeOf(
Null.prototype,
null
);
const bench = {
["__proto__"](times, withField) {
const instances = [];
for (let {prototype} = Test, i = 0; i < times; i++)
instances[i] = withField ?
{__proto__: prototype, i: Math.random()} :
{__proto__: prototype};
return instances;
},
create(times, withField) {
const instances = [];
for (let {prototype} = Test, i = 0; i < times; i++)
instances[i] = withField ?
create(prototype, {"i": new CEWValue(Math.random())}) :
create(prototype);
return instances;
},
new(times, withField) {
const instances = [];
for (let i = 0; i < times; i++)
instances[i] = withField ?
new Test(Math.random()) :
new Test;
return instances;
},
Null(times, withField) {
const instances = [];
for (let i = 0; i < times; i++)
instances[i] = withField ?
assign(new Null, {i: Math.random()}) :
new Null;
return instances;
}
};
function test(name, times, Class = Test) {
if (typeof process === 'object')
console.log(`\x1b[1m${name}\x1b[0m`);
else
console.log(`%c${name}`, 'font-weight:bold');
let instances = [new Class(0)];
console.time('cold - no fields');
instances = bench[name](times, false);
console.timeEnd('cold - no fields');
for (let i = 0; i < 5; i++)
instances = bench[name](times, false);
console.time('hot - no fields');
instances = bench[name](times, false);
console.timeEnd('hot - no fields');
console.time('cold ? fields');
instances = bench[name](times, true);
console.timeEnd('cold ? fields');
for (let i = 0; i < 5; i++)
instances = bench[name](times, true);
console.time('hot - fields');
instances = bench[name](times, true);
console.timeEnd('hot - fields');
verify(name, instances, Class);
console.log('');
}
function verify(name, instances, Class) {
console.assert(
instances.every(o => o instanceof Class && typeof o.i === 'number'),
`${name} failed`
);
}
function benchAll(times) {
test("new", times);
test("Null", times, Null);
test("create", times);
test("__proto__", times);
}
benchAll(10_000); |
@WebReflection if |
@ljharb it's |
This does not land cleanly on v18.x |
@juanarbol thanks, does #46239 land cleanly? if not, ill try to open a backport PR. |
Patch to benchmark: - create(prototype, {"i": new CEWValue(Math.random())})
+ assign(create(prototype), {"i": Math.random()}) :
after patch
const {assign, create, setPrototypeOf} = Object;
class Test {
constructor(i) {
this.i = i;
}
}
class CEWValue {
constructor(value) {
this.value = value;
}
get configurable() { return true }
get enumerable() { return true }
get writable() { return true }
}
class Null {}
setPrototypeOf(
Null.prototype,
null
);
const bench = {
["__proto__"](times, withField) {
const instances = [];
for (let {prototype} = Test, i = 0; i < times; i++)
instances[i] = withField ?
{__proto__: prototype, i: Math.random()} :
{__proto__: prototype};
return instances;
},
create(times, withField) {
const instances = [];
for (let {prototype} = Test, i = 0; i < times; i++)
instances[i] = withField ?
assign(create(prototype), {"i": Math.random()}) :
create(prototype);
return instances;
},
new(times, withField) {
const instances = [];
for (let i = 0; i < times; i++)
instances[i] = withField ?
new Test(Math.random()) :
new Test;
return instances;
},
Null(times, withField) {
const instances = [];
for (let i = 0; i < times; i++)
instances[i] = withField ?
assign(new Null, {i: Math.random()}) :
new Null;
return instances;
}
};
function test(name, times, Class = Test) {
if (typeof process === 'object')
console.log(`\x1b[1m${name}\x1b[0m`);
else
console.log(`%c${name}`, 'font-weight:bold');
let instances = [new Class(0)];
console.time('cold - no fields');
instances = bench[name](times, false);
console.timeEnd('cold - no fields');
for (let i = 0; i < 5; i++)
instances = bench[name](times, false);
console.time('hot - no fields');
instances = bench[name](times, false);
console.timeEnd('hot - no fields');
console.time('cold ? fields');
instances = bench[name](times, true);
console.timeEnd('cold ? fields');
for (let i = 0; i < 5; i++)
instances = bench[name](times, true);
console.time('hot - fields');
instances = bench[name](times, true);
console.timeEnd('hot - fields');
verify(name, instances, Class);
console.log('');
}
function verify(name, instances, Class) {
console.assert(
instances.every(o => o instanceof Class && typeof o.i === 'number'),
`${name} failed`
);
}
function benchAll(times) {
test("new", times);
test("Null", times, Null);
test("create", times);
test("__proto__", times);
}
benchAll(10_000); node v19.5.0, ubuntu 20.04
|
If this lands, I'd be happy to refactor this rule to a
prefer-syntax
rule, which also checks for things likeObjectAssign
with a literal as the first argument, use ofBoolean(x)
instead of!!x
, etc.