-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Object.keys throws for uninitialized module namespace object #1209
Comments
Thanks for filing! imo this is clearly a spec bug; any reflection operations on a TDZ-d module namespace object that solely expose keys, or enumerability/configurability/writable - not values (or thus the whole descriptor) - should work at all times. cc @allenwb to confirm this is a spec bug; @caridy @dherman @bterlson for their thoughts. |
Besides Object.keys, this affects:
And perhaps I missed some others. |
This is tricky! Spec looks good, at least in principle:
Do we really want to change this behavior? If we change this to make Likewise, changing the regular mechanism that govern |
Special case for namespace objects in relevant methods since its own property keys are known up-front without needing to dig deeper. |
I think a non-observable spec refactoring could absolutely allow special-cased internal methods on namespace objects - or, could even allow this to be “fixed” with fewer special cases (since the tdz is already a special case) |
A test in general we should apply every time we design the behavior of an
exotic object:
How faithfully can this behavior be emulated by a Proxy or membrane?
I don't foresee a problem here, but we need to check.
|
If I'm understanding correctly:
Taking these points together, I'm not sure how we can change Perhaps |
@zenparsing |
This is not a spec. bug, as such. Rather it is a direct consequence of the design of the MOP and how we choose to implement the MOP API for module namespace objects. The MOP itself is not really changeable as it is the foundation for how proxy objects and all other exotic objects interface with ES language features and the built-in library. The MOP defines the API that exotic objects can implement in order to support such features. But exotic objects are not required to support the full functionality of ordinary objects. Throwing is a valid way to implement most of the MOP API. For ES6 we discussed at a TC39 meeting how much of the MOP API that module namespace objects should usefully support. The consensus was that they were very exotic objects that existed to support a single function --dotted access to module imported bindings -- and that all they really needed to support was [[Get]]. That was pretty much what we did in ES 6. Most MOP operations on module namespace objects threw, or otherwise returned an error state Subsequent, people have tried to do things other than get property access with them and reported the failures as bugs. Even though the failures were "by design" some of them were fixed by adding additional functionality to the module namespace MOP implementation. But, they still are very exotic and can't be expected to be fully equivalent to ordinary objects. It doesn't bother me that Object.keys doesn't work on them as they weren't intended to be a module reflection mirror, But here is what you might do to "fix" the problem: The dotted property access functionality is provided by [[Get]] and is not dependent upon [[GetOwnProperty]]. Subject to the essential invariants, |
I've always thought they would be better off as getter/setters from the mental model perspective. This kind of discussion makes me realize the ergonomics would be better too. I believe the objection was that this would allow extracting the getter/setter functions and trying to use them, which was annoying to spec/implement. |
Yes, module name space objects were designed such that it would be fairly easy to for an implementation to compile mod.foo into a direct reference to the binding exported by "mod". That was really why we didn't want to expose getter functions. |
I think making [[GetOwnProperty]] return |
@GeorgNeis that should not be possible since the names are all known at the time of the object being available to user code - the only thing that would change over time is the values of the properties (and i think that any attempt to get the values should throw when in a tdz) |
Maybe there's a misunderstanding here. I assumed the suggestion is to return |
@GeorgNeis yes, i understand that that’s how the current spec operates, but that’s calling an un observable internal method. This issue suggests that we could call GetOwnProperty and enumerate the keys even if the values are not yet available. |
But the issue lies deeper than Object.keys, so just changing Object.keys will not be enough. See the list in my earlier post. And it's not clear to me what to do about some of the others. |
I agree it’s tricky. However, i feel like it should be achievable to allow the keys-only APIs to work while continuing to throw on the APIs that reference get/set/value. |
would this be a proper fix for this issue? diff --git a/spec.html b/spec.html
index 9797576..d71e3b1 100644
--- a/spec.html
+++ b/spec.html
@@ -8574,10 +8574,10 @@
<h1>[[OwnPropertyKeys]] ( )</h1>
<p>When the [[OwnPropertyKeys]] internal method of a module namespace exotic object _O_ is called, the following steps are taken:</p>
<emu-alg>
- 1. Let _exports_ be a copy of _O_.[[Exports]].
- 1. Let _symbolKeys_ be ! OrdinaryOwnPropertyKeys(_O_).
- 1. Append all the entries of _symbolKeys_ to the end of _exports_.
- 1. Return _exports_.
+ 1. Let _keys_ be a copy of _O_.[[Exports]].
+ 1. For each own property key _P_ of _O_ that is a Symbol, in ascending chronological order of property creation, do
+ 1. Add _P_ as the last element of _keys_.
+ 1. Return _keys_.
</emu-alg>
</emu-clause> |
No, this would not be a proper fix, because the fundamental issue is not about [[OwnPropertyKeys]]. |
@GeorgNeis what do you suggest? |
bump |
@devsnek Do you have anything that might move this forward? There doesn't seem to be an obvious solution: |
yeah i don't have any genius ideas to fix this. i was just thinking either someone will have come up with something or this can be closed. |
What about, change |
We seem to go round in circles, special casing |
allen's suggestion is probably the most sensical so far, so if that isn't found to be worth implementing i'd agree that this is working as intended. |
@ljharb But I think a better fix would be to special case https://tc39.github.io/ecma262/#sec-enumerableownpropertynames for the situation where O is an namespace exotic object and kind is "key". |
@allenwb sure, i mente the algorithm steps, not the method itself :-) special-casing in the way you suggest seems totally fine to me too. |
I just had a look at this. Would this be a proper fix? I tried to apply the suggestion by @allenwb. If it is, I'd just go ahead and open a PR for it. The only changes are in the outer 2. and 3.
|
@BridgeAR Modulo some minor editorial issues, that is the suggestion, yes. (Whether it constitutes a "proper fix" depends on what behavior you think is correct, which there isn't an objective answer to.) It would still need to be presented in plenary to land, though. |
Found in Node here and filed as a V8 bug here. It looks like
Object.keys
will throw an error when provided an uninitialized module namespace object whileObject.getOwnPropertyNames
won't.Comments from the V8 issue:
And
The bug is that
Object.keys
should not error just asObject.getOwnPropertyNames
does not error.\cc @ljharb
The text was updated successfully, but these errors were encountered: