-
Notifications
You must be signed in to change notification settings - Fork 32
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
Argument order for adopt()
#130
Comments
The precedent for "the optional thing being last" is also "virtually every modern userland API with optional arguments - even in node, where initially the convention was to always put the options bag last but to have optional arguments before it (that were optional even in the presence of the options bag), the ecosystem largely decided that was a brittle pattern and moved to the pattern we use in defaulting, where any argument that's omitted must also omit every argument that comes after it. Can you elaborate on |
This argument presupposes that the value is optional, however I contend that the value is vital. To explain this, let me start with a summary of the The {
using x = new Resource();
...
} You want as little user code as possible between The {
using stack = new DisposableStack();
const x = stack.use(new Resource());
...
} As little user-code as possible should run between resource acquisition (i.e., This is especially important if the return value of f(stack.use(new Resource1()), stack.use(new Resource2())); Here, we ensure resources are added to the stack in the order they are acquired, so that cleanup can occur in the correct order later. The purpose of the {
using stack = new DisposableStack();
const x = stack.adopt(new Resource(), res => res.close());
...
} The
Changing the order of arguments for While there are obvious overlaps,
In
This isn't an argument against the subject-first ordering, but an argument that the callback should potentially be further to the right of the subject. |
I'm strictly for the current behavior since |
const foo = stack.use(new Foo());
const bar = stack.adopt(new Bar(), it => {
somehowClean(it, 42);
}); vs const foo = stack.use(new Foo());
const bar = stack.adopt(it => {
somehowClean(it, 42);
}, new Bar()); In the second case, I don't immediately see what |
I'm 100% with you up to here.
So it sounds like the concern is that if the disposal function is NOT callable, there'd be an exception, before the value has been registered for disposal. That makes sense - except that all argument validation must (imo and by convention) be done before doing anything else with the values, which means that the argument order is irrelevant - a non-callable disposal function will always throw before the resource is registered for disposal if it's done in the same call.
Yes, they are; JSON functions were popularized in the ecosystem long before their inclusion in ES5, which is when filter was added. I'm not sure where I suggested to use |
This is far from the only concern, and if that is your only takeaway then I fear you have missed my point. Both It is
You mentioned it multiple times in #102, including this comment. Regardless, I'm still not convinced by your argument that the resource is optional. Yes, in theory you could reorder arguments to make |
I think the validation thing is more important to discuss. Regardless of the argument order, the callback needs to be checked for callability before registering the resource for disposal. |
That is what occurs in the current design as well, which is why I do not understand why you consider this to be more important. |
I'm just trying to interpret your long comment above. Whether the argument order is It sounds like you're saying that you care about having the resource appear first because of adherence to this RAII philosophy, and also because it's more readable to see the resource being disposed before reading the disposal callback? To confirm, is |
Yes
No, you cannot use let temp;
const x = (temp = new Resource(), stack.defer(() => onDispose(temp)), temp); |
I feel you may have misunderstood the difference in the APIs. Perhaps adding type information might clarify: class DisposableStack {
use<T extends Disposable | null | undefined>(disposableResource: T): T;
adopt<T>(nonDisposableResource: T, onDispose: (resource: T) => void): T;
defer(onDisposed: () => void): void;
}
{
using stack = new DisposableStack();
stack.use({ [Symbol.dispose]() { console.log(1); } });
stack.adopt(2, resource => { console.log(resource); } });
stack.defer(() => { console.log(3); });
stack.use({ [Symbol.dispose]() { console.log(4); } });
}
// prints:
// 4
// 3
// 2
// 1 |
Ron and I got on a call and we were able to get on the same page about the mental models and concepts, and I'm content with the proposal as-is, so we can consider this resolved, and the stage 3 condition met. |
This continues a discussion from #102 regarding the argument order of
adopt()
, the outcome of which is a condition for Stage 3 advancement.As I understand it, it is @ljharb's position that the argument order should be
adopt(onDispose [, value])
, which would potentially makedefer(onDispose)
unnecessary due to overlap. The precedent for this would be the existence of the optionalthisArg
in existing APIs likeArray.prototype.map
,.filter
,.forEach
, and the optionalinitialValue
argument toArray.prototype.reduce
and.reduceRight
.It is the champion's position that
adopt(value, onDispose)
is the correct argument order, with the precedent being existing APIs such asJSON.parse
,JSON.stringify
, andArray.from
, and that there are inherent differences in how.adopt
is intended to be used vs..defer
that indicate these should be separate methods.Rather than go into more detail for each argument in the issue description, I'll post specifics related to my rationale in the comments below.
@ljharb: If you have any further details you'd like to provide, please let me know in the comments as well. If I have misrepresented your position in any way, let me know and I can update the issue description to more accurately summarize your position.
The text was updated successfully, but these errors were encountered: