-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
lib: Symbol.dispose should be enabled with experimental flag #54329
Conversation
Review requested:
|
Isn't Symbol.dispose already polyfilled tho? What happens to those implementations when the flag isn't provided? |
b383d03
to
1cf4567
Compare
All A userland polyfill should be able to polifill |
What I mean is, if a flag is required to enable the proposal, then shouldn't the Symbol not exist without the flag? |
With this change, the interal symbol exists on primordial It is there for convinience of implementaion like |
@@ -160,6 +160,9 @@ function prepareExecution(options) { | |||
} | |||
|
|||
function setupSymbolDisposePolyfill() { | |||
if (!getOptionValue('--experimental-explicit-resource-management')) { | |||
return; | |||
} |
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.
The fact that we have those symbols available allows for TypeScript to implement this correctly on their side. I don't think having these symbols in place cause any harm
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.
Yeah I don't see the vlaue in putting this (after a year of usage) behind a flag and it already falls back gracefully to not polyfilling if Symbol.dispose is already defined by V8.
The symbol is still here. Like other active developing ECMAScript features needing a It gives a false impression that the explicit resource management proposal is shipped in the Node.js without a flag. |
How? Maybe I misunderstood this pr. The reasoning behind adding this in this way was that, even thought the syntax was not there, the symbol could be called by relevant tools/transpilers and we could experiment with this API. All of those API would now be behind a flag, essentially regressing support for this. I'd be ok to do that if that proposal was not moving forward, but it seems it is moving forward, so it seems a step back in removing these to add it later. |
I think a general principal to experiment an early developing globally accessible APIs/syntax should need a flag, reducing the chance of regression or broadly exposed breaking changes. I am fine leaving |
TypeScript or any other transpilers can experiment new ECMAScript features without Node.js unconditional polyfills. Like the following transpile result, it doesn't need Node.js to unconditionally polyfill a global example"use strict";
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
if (value !== null && value !== void 0) {
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
var dispose, inner;
if (async) {
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
dispose = value[Symbol.asyncDispose];
}
if (dispose === void 0) {
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
dispose = value[Symbol.dispose];
if (async) inner = dispose;
}
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
env.stack.push({ value: value, dispose: dispose, async: async });
}
else if (async) {
env.stack.push({ async: true });
}
return value;
};
var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
return function (env) {
function fail(e) {
env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
env.hasError = true;
}
function next() {
while (env.stack.length) {
var rec = env.stack.pop();
try {
var result = rec.dispose && rec.dispose.call(rec.value);
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
}
catch (e) {
fail(e);
}
}
if (env.hasError) throw env.error;
}
return next();
};
})(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
});
const foo = {
[Symbol.dispose]() {
console.log('dispose');
}
};
var _;
const env_1 = { stack: [], error: void 0, hasError: false };
try {
_ = __addDisposableResource(env_1, foo, false);
}
catch (e_1) {
env_1.error = e_1;
env_1.hasError = true;
}
finally {
__disposeResources(env_1);
} So with a global |
I'm not sure what the issue is though? It's an experimental feature, it's subject to change, we have several similar situations across Node.js (though no polyfills). We do not implement the explicit resource management proposal though. We don't have
Sure but this isn't much of a globally available API? It's like Matteo said just a hook for third-party tools (like TypeScript) to use Symbol.dispose/asyncDispose on APIs. I agree when there is breakage potential (like exposing EventTarget globally) we need a flag + a major with the flag + a major with an opt out flag in order to make migration easier for the ecosystem. But if this proposal changes/breaks we break our (intentionally experimental for over a year) APIs. We can document the implication of an API being experimental better though to make it clear what it means. |
It is globally available |
@legendecas yes, we implement the minimal amount we need in order to be hookable and allow interoperability and experimentation. We do not implement the syntactic parts. This is similar to many web APIs where we implement the subset it makes sense for Node to implement in core. The way people have been using this this past year is through tools like TypeScript, it's functionally not usable without a third-party tool until V8 implements it.
Hence the "much" part :) It's very unlikely (unless I'm not considering something obvious) to conflict with existing user code or cause breakage. |
I think my point is that an unfinished feature is unconditionally exposed on the global. It should be experimented with a flag under active development. Like, all actively developing new ECMAScript features will require experimental flags in V8, and it will be confusing that Node.js only implement the language built-in incompletely but enabled it unconditionally.
I don't agree ECMAScript features are similar to Web APIs we implement partially by intention. This PR didn't remove |
0ab8ce9
to
c2b0107
Compare
Updated to emit an experimental warning when either The experimental warning will be disabled when either |
c2b0107
to
8d499ec
Compare
The TC39 explicit resource management proposal is still at stage 3 and under active development. It must be enabled with an experimental flag `--experimental-explicit-resource-management`. The flag implies that the V8 option `--js-explicit-resource-management` to be enabled. When `--experimental-explicit-resource-management` flag is not set, an experimental warning is emitted.
8d499ec
to
8accb84
Compare
I don't think it's good UX to add an experimental warning a year into it, but if this was a new feature I would have been fine with an experimental warning. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #54329 +/- ##
==========================================
- Coverage 87.11% 87.04% -0.07%
==========================================
Files 647 647
Lines 181754 181957 +203
Branches 34885 34895 +10
==========================================
+ Hits 158332 158393 +61
- Misses 16738 16861 +123
- Partials 6684 6703 +19
|
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, we should likely have been emitting a warning from the beginning for this feature.
Can you please add a test that uses the using
feature?
As in with --experimental-strip-types? |
My understanding is that --js-explicit-resource-management does actually enable the syntax. |
The flag is present but the implementation is unfinished. The syntax support is still limited and not functional on the node.js main branch. |
It'd be nice if passing |
Right, boolean flags are not possible to be distinguished whether a |
I still think we shouldn't do this a year into it (for developer expectations/ux concerns), but I think in retrospect it should have had an experimental warning and we should change the process to require TSC consensus before landing new globals (especially experimental ones) since that's a cross cutting concern. |
Also at the very least it should have been semver-major by default without other considerations since it added a new global |
I can stand by the ship being sailed on emitting the experimental warning on this one too. @nodejs/tsc what do you all think? |
I don't think this should land as is. It will break existing users. |
@MoLow the PR only emits experimental warnings. Enable flag |
Let's not focus on this particular feature (Symbol.dispose) can we get TSC consensus/evaluation of safety on requiring TSC consensus for polyfilling/adding experimental JS APIs with (even tiny) potential breakage potential? |
Closed in favor of #54330. |
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: #54330 Refs: #54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: nodejs#54330 Refs: nodejs#54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
Explicitly document that adding an API to the global scope requires `semver-major` label. Waiving the `semver-major` requires a regular TSC consensus process. PR-URL: nodejs#54330 Refs: nodejs#54329 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
The TC39 explicit resource management proposal is still at stage 3 and
under active development. It must be enabled with an experimental
flag
--experimental-explicit-resource-management
. The flag impliesthat the V8 option
--js-explicit-resource-management
to be enabled.When
--experimental-explicit-resource-management
flag is not set, anexperimental warning is emitted.
Unconditional global presense of
Symbol.dispose
can be confusing thateitehr
DisposableStack
,AsyncDisposableStack
andSuppressedError
are not implemented.