Closed Bug 312116 (js-catchall) Opened 15 years ago Closed 9 years ago

should support catchall getters/setters

Categories

(Core :: JavaScript Engine, enhancement, P2)

enhancement

Tracking

()

RESOLVED WONTFIX

People

(Reporter: shaver, Unassigned)

References

Details

Attachments

(1 file, 1 obsolete file)

We want to be able to do things like:

js> o = { get *(name) { return name + "!"; } };
[object Object]
js> o.foo
foo!

Don't you agree?
Attached patch WIP (obsolete) — Splinter Review
This makes getters and toSource work, but still needs:

- setters
- Object.prototype.__define[GS]etter__ support
- a distinguished XDR representation of the anyname atom for proper
serialization behaviour

Ahoy!
It would be great if it could also [gs]et constructs like

Object.foo::@bar

for E4X stuff.
Sean: gimme a test case?  Synthesizing the XML data-model parts sounds like
pain, but I'll keep an open mind.
Assignee: general → shaver
(In reply to comment #3)
> Sean: gimme a test case?  Synthesizing the XML data-model parts sounds like
> pain, but I'll keep an open mind.

Shaver: it'll all just work if you handle an id for which JSID_IS_OBJECT
evaluates to true.

/be
Attached patch WIP 2Splinter Review
Now supports setters, and __define[GS]etter__(*, function(){}).  Also should be XDR-friendly (haven't tested it yet).  Sucks to not be able to remove getters or setters, but I bet there are good reasons for that, or something.

Need to figure out how having a default getter should interact with the 'in' operator, if at all.

Haven't tested Sean's testcase yet, but I don't think it'll work -- there is code in there to explicitly defend again object-named properties on non-XML objects, and I'm not sure I want to remove that check without a lot more auditing.
Attachment #199239 - Attachment is obsolete: true
Attachment #200666 - Flags: superreview?(brendan)
Attachment #200666 - Flags: review?(mrbkap)
Comment on attachment 200666 [details] [diff] [review]
WIP 2

The anya/anyv code should be a common subroutine.  But more important: why can't the special case, instead of slowing down the general js_SetProperty etc. control flow, be done under the hood, by a getter/setter pair defined just for the anyname object id?

/be
Another problem with this, beyond brendan's wholly unreasonable insistence that I make only users of this capability pay for it :), is that once you have a fallback setter you can't create a new "normal" property on such an object.  You have to resort to defining getters/setters, which is pretty gross.

Object.prototype.__addProperty__(propName, initialValue) ?  It would throw if the property already existed.

MOPs are hard, waah.
Mass abdication.
Assignee: shaver → nobody
Attachment #200666 - Flags: superreview?(brendan)
Alias: js-catchall
Summary: should support fallback getters/setters → should support fallback getters/setters (JS2/ES4 catchalls)
(In reply to comment #0)
> Don't you agree?

Much better if we can get...

js> o = {get *(){a=arguments; return a[2]+' in '+a[1]+' in '+a[0];}};
[object Object]
js> o.my.foo.bar
bar in foo in my

Blocks: 371033
Important note: ES4 catchalls aren't _fallbacks_ -- they're always called, and before default behaviour.  There is still discussion underway about how to signal that the default behaviour should be used, possibly by throwing a specific exception (like the iteration protocol).

I may also propose that when in get * for a property p, the catchall is skipped on a nested get of p.
Summary: should support fallback getters/setters (JS2/ES4 catchalls) → should support catchall getters/setters
Blocks: js1.8.5
(In reply to comment #10)
> Important note: ES4 catchalls aren't _fallbacks_ -- they're always called, and
> before default behaviour.

For dynamic properties (ES4 folks will know what this means), not for fixtures.

> There is still discussion underway about how to
> signal that the default behaviour should be used, possibly by throwing a
> specific exception (like the iteration protocol).

That's actually the proposal. It needs detailing but we are not likely to change to another out-of-band signal.

> I may also propose that when in get * for a property p, the catchall is skipped
> on a nested get of p.

We're against new syntax in object initialisers for catch-alls, as of today's ES4 working group meeting. We see no need given const in an object initialiser before the property label making a read-only, don't-delete property (a fixture), and property names allowing namespace qualifiers in initialisers:

var obj = { const meta::get: function (id) ...,
            const meta::set: function (id, val) ...,
            ... };

SpiderMonkey has namespace qualifiers via E4X. It has const of a sort, but the details of const hoisting and use-before-set don't crop up here in initialisers.

/be
Adding this to the 1.9.1 triage queue by marking this wanted1.9.1?.  If this should be a blocker, please mark accordingly.
Flags: wanted1.9.1?
Priority: -- → P2
Flags: wanted1.9.1? → wanted1.9.1+
Adding catchall getters could make it easier to steal information from certain sites.  For example, consider a site that serves a text file containing only one word or hex string.  With script src and a catchall getter, a script on another site could find out what the string is.
Why the focus around a * getter?

Isn't * a valid property name if you are using ['*']?

ie: Isn't this valid?
var o = {};
o.__defineGetter__('*', function() 'foo');
o['*']; // foo

IMHO, a catchall getter/setter should work more like __noSuchMethod__.
ie: __get__ and __set__.
o.__get__ = function(propName) ...;
o.__set__ = function(propName, value) ...;

(In reply to comment #9)
> (In reply to comment #0)
> > Don't you agree?
> 
> Much better if we can get...
> 
> js> o = {get *(){a=arguments; return a[2]+' in '+a[1]+' in '+a[0];}};
> [object Object]
> js> o.my.foo.bar
> bar in foo in my

I don't see to much need for that. Shouldn't using closures and getters together handle that?

var o = {
  __get__: function(a) {
    return {
      __get__: function(b) {
        return {
          __get__: function(c) {
            return c + ' in ' + b + ' in ' + a;
          }
        };
      }
    };
  }
};
The use of * is new syntax, not a property name to be equated to "*". Using * will not conflict with any nameable property's id, including "*".

Catch-alls are out of favor in TG1, at least among a few heavy hitters. More on this in es-discuss when I have time (next few days).

/be
(In reply to comment #13)
> Adding catchall getters could make it easier to steal information from certain
> sites.  For example, consider a site that serves a text file containing only
> one word or hex string.  With script src and a catchall getter, a script on
> another site could find out what the string is.

That issue could be easily negated by disabling the ability to set a catchall getter or setter on the global object.
I see use for setting local getters and setters on the global object, however I see no logical use for setting a catchall getter or setter on the global object.

Of course, I recommend this being dependent on a not allowed by default option rather than being hardcoded as not permitted.
While this security issue you mention exists within the browser environment, it does not have any issue within a server environment. Afact jslibs already provides ObjEx which allows for absolute control over spying and modifying all property get/set/add/del actions on a special object. It would just be preferable for catchall getters/setters to be implemented as they would likely perform better for the majority of possible cases why ObjEx would be used.
Severity: normal → enhancement
Flags: wanted1.9.1+
We just ran into a case where this would help unimplemented methods in the window's console object called indirectly via apply or call fallback gracefully. Would be nice to have, but based on the date on the WIP patch, this hasn't been looked at for awhile.
I think you want to make the window.console object be a proxy instead, then.  There are threads on es-discuss that show how to emulate __noSuchMethod__ in these cases using proxies.

I think this bug is WONTFIX: proxies are the way forward, catchalls have been dropped for all plans for ES/JS that I know of.
Status: NEW → RESOLVED
Closed: 9 years ago
Resolution: --- → WONTFIX
ok, thanks for the pointer.
I see 2 problems with PROXY

1. When you make a variable winProxy as a proxy for window object, all those place where somebody reference variable winProxy you get catchall mechanism but if some code refer window you dont have catchall mechanism.

2. When you make a variable winProxy as a proxy for window object, when ever somebody refer winProxy.document it execute few lines of JavaScript code even though "document" is a built-in/native property of "window" object. Hence resulting code become very inefficient. 

PROXY are useful when you want to hide an object, 
but not when you want add additional features for existing object.
Biju:

Re 1: don't do that, then. Confine the window object properly, expose only the proxy to all consumers who need to see the catchalls.

Re 2: "very inefficient" needs profiling data as proof. We use proxies for window objects in Firefox 4. They're efficient enough. Scripted handler traps are not yet trace-JIT-inlined but that's the plan, which will pretty much erase the cost.

/be
(In reply to comment #21)
> Re 2: "very inefficient" needs profiling data as proof. We use proxies for
> window objects in Firefox 4. They're efficient enough. 
Good...

> Re 1: don't do that, then. 
:(
Note for myself in the future, and anyone interested:

http://soft.vub.ac.be/~tvcutsem/proxies/ looks like it explains (pretty clearly, actually) how you can define a proxied catch-all getter or setter, through a handler.get or handler.set method.  His "Hello, Proxy!" example literally generates a response for anything...
(In reply to comment #23)
> Note for myself in the future, and anyone interested:
> 
> http://soft.vub.ac.be/~tvcutsem/proxies/ looks like it explains (pretty
> clearly, actually) how you can define a proxied catch-all getter or setter,
> through a handler.get or handler.set method.  His "Hello, Proxy!" example
> literally generates a response for anything...

I've been cribbing from http://wiki.ecmascript.org/doku.php?id=harmony:proxies.
You need to log in before you can comment on or make changes to this bug.