In the same success it may be a simple very-generic meta-constructor (that is, Object.create) which may accept a className. That what have been discussed many times (including the only approach for today with injecting with __proto__), including in the recent talk https://mail.mozilla.org/pipermail/es5-discuss/2010-September/003708.html.

E.g.:

Object.create({
   prototype:<...>,
   class: "Array",
   descriptor: {
     ...
   }
});

or (the current, but extended way -- which won't bring backward compats issues)

Object.create(prototype, descriptor, "Array");


For what to create a proxy? It's only for catch-traps (yes, it may be used additionally to create a _catcher_ with "Array" [[Class]], but without additions -- i.e. if a user wants just to inherit from Array.prototype and to have all arrays' stuff -- proxies are not needed to him).

Dmitry.

On 02.10.2010 8:30, Tom Van Cutsem wrote:
We have previously discussed the Proxy.create(handler, proto, className) design and I think it's feasible. One issue is what should happen to the proxy's [[ClassName]] when it becomes fixed. In the current design, a fixed object proxy can be made indistinguishable from a regular object. That's no longer the case if the fixed proxy should retain its custom [[ClassName]] (which I think is desirable).

That said, if proxies would be able to virtualize something like [[ClassName]], I think the array subclassing use case can be supported as follows (I'm sure there's a much better way to do this, but this is just a proof-of-concept):

function createArray(proto, initArray) {
  // proto is assumed to delegate to Array.prototype
  // initArray is assumed to be a real Array
  var handler = {
    get: function(r,n) {
      if (!initArray.hasOwnProperty(n)) {
        return proto[n];
      } else {
        return initArray[n];
      }
    },
    set: function(r,n,v) {
      return initArray[n] = v;
    },
    // other traps
  };
  return Proxy.create(handler, proto, "Array");
};

var SubArray = Object.create(Array.prototype);
SubArray.last = function() {
  return this[this.length - 1];
};

var myArray = createArray(SubArray, [1,2,3]);
myArray.length; // 3
myArray.last(); // 3
myArray[10] = 42;
myArray.length; // 11
myArray.last(); // 42
Object.prototype.toString.call(myArray); // [object Array]
myArray instanceof Array; // true
myArray.toString(); // 1,2,3,,,,,,,,42

I tested this in a recent tracemonkey shell with support for Proxies and it seems to work (except that currently, of course, proxies cannot virtualize [[ClassName]] so the proxy-array still prints as [object Object])

2010/10/1 Juriy Zaytsev <[email protected] <mailto:[email protected]>>



    On Fri, Oct 1, 2010 at 10:00 PM, Oliver Hunt <[email protected]
    <mailto:[email protected]>> wrote:


        On Oct 1, 2010, at 6:55 PM, Brendan Eich wrote:

        > On Oct 1, 2010, at 6:24 PM, Oliver Hunt wrote:
        >
        >> I really don't like the idea of using proxies simply to
        essentially create an array with a custom prototype.
        >
        > Implement proxies, then we'll talk :-P.
        >
        >
        >> My understanding of what is wanted (in terms of subtyping
        an array) is an ability to have something like
        >>
        >> var arr = new MyArray()
        >>
        >> Where 'new MyArray' behaves in essentially the same manner
        as 'new Array', however it produces an object along the lines of
        >>
        >> <an array instance> <- <a custom prototype> <- <array
        prototype>
        >
        > I don't think the use-case is satisfied by a direct Array
        instance, whatever its proto. That's the rub.

        What part of the use case is not covered?  From reading the
        blog post (which suggests something similar to this) kangax
        says the problem with this solution is the use of the
        non-standard __proto__, not that it doesn't achieve the
        desired result


    Object.create([]) doesn't solve the problem of subclassing an
    array, since created object is still a plain Object object and so
    has [[Get]] and [[Put]] that act like Object's ones, not Array ones.

    var o = Object.create([]);
    o[2] = 'x';
    o.length; /* 0, not 3 as it should be */

    o.length = 0;
    o[2]; /* "x", not undefined as it should be */

    In ES3 (w/o extensions) you can't do much about it, but in ES5
    it's possible to fiddle with length getter/setter to make object
    act like an array (the performance of such implementation turns
    out to be incredibly slow, for obvious reasons).

    So now when you solved "magic" length property (considering that
    we're in ES5), and have a plain Object object with [[Prototype]]
    referencing Array.prototype, you still have immutable [[Class]].
    So Array.isArray would return false for this pseudo-array object
    (it could be somehow overwritten to account for it, but this is
    kind of getting too far); and then there are places in spec, where
    wrong [[Class]] ("Object", not "Array") will make for a completely
    different outcome. For example, JSON.stringify:

    var o = Object.create([]);
    o[2] = 'x';

    JSON.stringify(o); // "{"2":"x","length":0}" not [null,null,"x"]

    Settable [[Prototype]] helps because you can just create an array
    object, then inject something into its prototype chain (right
    before Array.prototype). And that extra object can have any
    methods you wish on subarray instances — all without polluting
    global Array.prototype.

    [...]

-- kangax

    _______________________________________________
    es-discuss mailing list
    [email protected] <mailto:[email protected]>
    https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to