duktape icon indicating copy to clipboard operation
duktape copied to clipboard

Using ownKeys trap for custom objects not working

Open adam-veego opened this issue 5 years ago • 3 comments

Hey,

I have some kind of a custom object that uses proxy to virtualize properties and pass the properties access to an inner handler, so writing a.b.c.d will access each of the levels one by one with the getter function and push the next inner object (or final leaf value) to the stack along with its own proxy and other things. However, when I trap ownKeys for enumeration, to use in for-in clauses, my returned properties array seems to be ignored, and no cycle of the for loop ever runs.

I read this may have to do with the absence of getOwnPropertyDescriptor trap. Is it actually that as long as this trap is not handled by duktape, whatever returned in ownKeys is meaningless and for-in will never be executed for customized properties of user-implemented objects? Is there a different way to implement that while still using proxies? I cannot define each separate property of the objects explicitly, because they are dynamic - the usage of general getters and setters is essential for this specific purpose.

Both calling duk_def_prop for each property in each access to the custom object did not resolve the problem, even calling duk_get_prop_desc for each property of the object immediately afterwards does not even return what I just added. Also adding has trap to the proxy object and having it always return TRUE had no effect whatsoever.

I guess what I'm doing is pretty unusual and may seem a bit weird but it enables necessary semantics of access to internal data structures through javascript. Is there a solution currently supported? Am I doing something wrong and using the correct solution improperly? Or should I give up the usage of for-in clauses for this purpose with the current version of duktape.

Thanks.

adam-veego avatar Jul 23 '19 11:07 adam-veego

As you noted, the values returned by ownKeys must also exist in the target object (https://www.ecma-international.org/ecma-262/10.0/index.html#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys):

duk> O = {foo:1, bar:2, quux: 3}
= {foo:1,bar:2,quux:3}
duk> P = new Proxy(O, { ownKeys: function () { return ['foo', 'bar', 'quux', 'nosuch'] } })
= {foo:1,bar:2,quux:3}
duk> for (var i in P) { print(i); }
foo
bar
quux
= undefined

In the above, 'nosuch' does not exist in the target so it is not enumerated.

To virtualize enumeration one would need to define a "getOwnPropertyDescriptor" trap, but unfortunately Duktape doesn't support it at present.

Or should I give up the usage of for-in clauses for this purpose with the current version of duktape.

Unfortunately so :/

svaarala avatar Jul 23 '19 14:07 svaarala

Thank you for the quick and to the point reply. How difficult would it be to implement this trap, or even locally make a small custom code change to bypass the ECMA specification? This may be one pretty significant thing that enables duktape to serve as a fast scripting tool that utilizes internal interfaces of generic platforms, although I understand the way I'm using it is probably unusual.

adam-veego avatar Jul 23 '19 14:07 adam-veego

Adding specific support for the trap for enumeration would not be too difficult, but it also affects other places. Some of the existing Proxy limitations will need some reworking rather than incremental addition of functionality, so I'll probably address this and the remaining limitations in a larger rework.

As for the use case, virtualizing enumeration is IMO not a very unusual use case, so I can definitely understand why it would be useful.

svaarala avatar Jul 23 '19 14:07 svaarala