archives

« Bugzilla Issues Index

#4083 — Module exotic object and GetOwnProperty?


http://people.mozilla.org/~jorendorff/es6-draft.html#sec-module-namespace-exotic-objects-getownproperty-p

Why does [[GetOwnProperty]] throw here?


Mostly to avoid any implication that the properties that correspond to module exports are specifically either data properties or accessor properties. (they really are neither). Returning undefined wouldn't be right either, because that would imply that the property doesn't exist.

More generally module objects are very exotic and the reflection that is supported on them is very limited. You can enumerate the the exported name property and test to see whether a property exists or access its values, but not very much else.


My concern is that some spec algorithms use [[GetOwnProperty]] and now they are going to throw.

Sorry for rehashing this but what were the reasons we decided to not uses getters for these?


(In reply to Erik Arvidsson from comment #2)
> My concern is that some spec algorithms use [[GetOwnProperty]] and now they
> are going to throw.
>
> Sorry for rehashing this but what were the reasons we decided to not uses
> getters for these?

Then the get functions would be exposed and could be passed around. Instead we over-ride [[Get]].

What algorithms that use [[GetOwnProperty]] would be reasonably applied to a module namespace object? If we really need to support that, the way to do it would be for them to expose the attributes of a data property, rather than an accessor.


(In reply to Allen Wirfs-Brock from comment #3)
>
> What algorithms that use [[GetOwnProperty]] would be reasonably applied to a
> module namespace object?

I just did a quick check (including HasOwnProperty which is defined in terms of [[GetOwnProperty]]) and I didn't see any that would be an issue


The only one I can think of that will be very confusing to people is getOwnPropertyDescriptor.

> Then the get functions would be exposed and could be passed around. Instead we over-ride [[Get]].

Why is that a problem?

Even if you don't want that to work we could make getters work. They could do some kind of "brand check" to ensure that the function is called with the right this.


(In reply to Erik Arvidsson from comment #5)
> The only one I can think of that will be very confusing to people is
> getOwnPropertyDescriptor.

The existence of Proxy makes any use of the Object.* meta operations upon arbitrary objects totally unpredictable .

>
> > Then the get functions would be exposed and could be passed around. Instead we over-ride [[Get]].
>
> Why is that a problem?
>
> Even if you don't want that to work we could make getters work. They could
> do some kind of "brand check" to ensure that the function is called with the
> right this.

To me, the whole point of having a MOP is that specialized object behaviors can be defined without exposing implementation details like the use of accessor properties. What benefit is there to requiring an implementation to expose accessor properties (other than making down version trans-compilation easier in the absence of Proxies).


Anything that is exotic requires a "proxy" which will lead to higher implementation costs and performance penalty.

This is not about transpilers.


Strongly agreed. The presence of a well-specified MOP does not change the fact that exotic objects are painful exceptions to the language for both authors and implementers. We should not be introducing more exotic objects like this.


(In reply to Domenic Denicola from comment #8)
> Strongly agreed. The presence of a well-specified MOP does not change the
> fact that exotic objects are painful exceptions to the language for both
> authors and implementers. We should not be introducing more exotic objects
> like this.

Module name space objects, howeever they are specified are highly exotic. Look at the rest of their behavior particularly their [[Get]] behavior. That burden is there however you look at it.

The current specification gives implementors maximal flexibility in how they go about support their module linkage semantics.

I'd entertain an argument that that their [[GetOwnProperty]] should report the exported names as non-configurable, non-writeable, enumerable data properties. But requiring exposing them as an accessor property with an visible per name per namespace get attribute function is a very bad idea.


(In reply to Allen Wirfs-Brock from comment #9)
> I'd entertain an argument that that their [[GetOwnProperty]] should report
> the exported names as non-configurable, non-writeable, enumerable data
> properties.

Non-configurable and non-writeable is not possible without violating the essential internal method invariants. Only non-configurable and writeable is valid. (Even if a property is reported as writable, it's not required to expose a mechanism to give the property a different value.)


Isn't it a violation to throw as well? It should be.


(In reply to Erik Arvidsson from comment #11)
> Isn't it a violation to throw as well? It should be.

No, throwing is always allowed - otherwise revocable proxies wouldn't be possible. Or in general all proxies because user code in proxy traps can throw.


(In reply to André Bargull from comment #10)
>
> Non-configurable and non-writeable is not possible without violating the
> essential internal method invariants. Only non-configurable and writeable is
> valid. (Even if a property is reported as writable, it's not required to
> expose a mechanism to give the property a different value.)

Yes, of course! It would have to be writable: true. Of course, [[Set]] and [[DefineOwnProperty]] still unconditionally return false (in other words, refuse to modify the value)


I'm not going to change this, as none of the arguments presented seem sufficient to change this intentional design decision. Exposing get functions via accessors property descriptors still seems like a bad idea. Exposing them as data properties would require saying that they are writable: true. and that seems likely to mess up user written reflection algorithms.

Throwing here seems like appropriate notification that you shouldn't be reflecting upon module namespace objects.


Allen, you did not answer Erik's question


>> Then the get functions would be exposed and could be passed around. Instead we over-ride [[Get]].
>
> Why is that a problem?

Indeed, it seems to be no more of a problem than exposing `import * as foo from 'foo'; export function getMNOProperty() { return foo.bar; }`.

I think it's not appropriate to close this without further discussion given there is implementer feedback that this will make the spec harder to implement.


(In reply to Domenic Denicola from comment #15)
> Allen, you did not answer Erik's question
>
>
> >> Then the get functions would be exposed and could be passed around. Instead we over-ride [[Get]].
> >
> > Why is that a problem?
>
> Indeed, it seems to be no more of a problem than exposing `import * as foo
> from 'foo'; export function getMNOProperty() { return foo.bar; }`.


It would force an implementation to create and expose a distinct get function for each property of a Module Namespace object that is exposed via [[GetOwnProperty]]. Those function would only need to exist because of the need to populated the property descriptor. While those functions could be lazily created, they would presumably need to be indefinitely retained, because there would be a reasonable expectation that:
Reflect.getOwnOPropertyDescriptor(someModNS. "foo").get === Reflect.getOwnOPropertyDescriptor(someModNS. "foo").get

But this is really about about something much deeper. Module Namespace objects are not ordinary objects and their properties are not accessor properties.

Their essential behavior is defined in terms of their [[Get]] and [[Set]] internal methods, not in terms of [[GetOwnProperty]] and [[DefineOwnProperty]].

Changing that intentional part of the design would be a much bigger issues, than what we have been talking about so far. (And not the topic of this bug)

>
> I think it's not appropriate to close this without further discussion given
> there is implementer feedback that this will make the spec harder to
> implement.

There are many implementors and many opinions.
(No disrespect to Arv, he just made a general observation and one that I don't necessarily disagree with. There are always trade-off involved when choosing to define exotic objects. The general observation applies at least as much to Typed Arrays as it does to Module Namespace objects.)

ES6 is done, unless you are saying you don't think we should go for GA approval in June.

Feel free to proposal a change for ES7, but as far as ES6 is concerned WONTFIX seems like exactly the right resolution (giving that we lack a WORKSASINTENDED).
The ES6 design is quite future proof in this regard (something that could not be said if [[GetOwnProperty]] did anything other than throw).


We talked a bit about this.

Data properties are fine. However, it would be preferable if getOwnPropertyDescriptor returns

{
value: ...
configurable: false,
writable: true
enumerable: true
}

Note, that reporting writable false would be a violation since the value might change.

Since [[Set]] always returns false without doing anything else this is no violation of the internal methods.