Instance constructors

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Instance constructors

David Bruant-4
Hi,

Currently, WebIDL states (4.5.3):
"There MUST exist an interface prototype object for every interface defined (...). The interface prototype object for a particular interface has properties that correspond to the attributes and operations defined on that interface."

This is likely to be motivated by the need to enforce that all "instances" inherit all constants, attributes and operation from the interface.
This is fine for operations and constants but forces something i consider hacky for attributes which is imposing them as getter/setters on the interface and use the |this| to emulate a value-per-instance behavior.

One problem this hack is a workaround of is that JavaScript lacks of a mechanism to enforce that things inheriting from the same prototype object have some common properties.
When running "Object.create(someObject);", someObject has no way to initialize the object being created while it may be relevant for it to add properties.

I'd like to propose the addition of a new internal property of object which is [[Initializer]] which is a function that is called when an object is created.
Example:
-----
// assuming o is an object with o [[Initializer]] = function(){this.a = 1}
// Maybe it's a regular object, maybe it's an host. Whatever.
var oo = Object.create(o); // calling o.[[Initializer]] with the object being created as |this|

Object.getOwnPropertyDescriptor(o, 'a'); // {value: 1} (+true, true, true)
-----

Actually the idea of an internal [[Initializer]] is not very far from the "constructor" in the classes proposal [1]. I would expect "super" to work the same which is calling [[Prototype]].[[Initializer]].
I think that [[Initializer]] should be assigned at initialization time and not be settable afterward, like for [[Prototype]]. Maybe could it be assigned with an additional Object.create argument/obj init syntax special field?

Open issue:
- How to pass arguments to [[Initializer]]? (is it absolutely necessary?)

Back to WebIDL, it could define custom [[Initializer]] for each interface in order to create the relavant properties at the own layer as data properties rather than the craziness of getter/setter at the interface level.

David

[1] http://wiki.ecmascript.org/doku.php?id=harmony:classes

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

Allen Wirfs-Brock
let instance = Object.create(o);
instance.constructor(/* constructor args */)

This assumes that the new instance will inherit "constructor" from its prototype chain (possibly all the way to Object.prototype.constructor (.i.e. Object).
If you are careful to always code your constructors to return this, you can shorten it to:

let instance  = Object.create(o).constructor(/* constructor args */);

As I think I have talked about in the past.  For ES.next I think we should extend the semantics of new to be approximately:

function ESNewOperator( rhs, args) {
   if (rhs has [[Constructor]] ) return rhs.[[Constructor]].apply(undefined,args);
   let instance = Object.create(rhs);
   instance.constructor(...args);
   return instance;
}
( a few additional error conditions need to be added)

This allows the new operator  to make sense (and work in an internally interoperable manner) for both prototypical and classical inheritance

For example:

let proto = {
   depth: 0;
   constructor: function() {this.depth +=  1};  /* get parent's depth, increment it, and store as own property of instance */
}

let lev1 = new proto;
let lev2 = new lev1;
let lev3 = new lev2;

I'm being terse in my explanation, but this would essentially giving ES the ability to really do self-style prototypical instantiation without getting in the way to existing constructor-based instantiation.  Newing an arbitrary object creates a new instance whose [[Prototype]] is the newed object and then calls the inherited constructor.   The constructor method servers as the initialize method.  Such a constructor  can be called either explicitly as has traditionally been done in JS or it call be called implicitly by newing an that inherits its as its constructor property.

Regarding, WebIDL.  It seems to me, that it just needs an extended attribute to specifies which attributes are instance attributes rather than prototype attributes.

Allen




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

David Bruant-4
Le 24/09/2011 00:35, Allen Wirfs-Brock a écrit :

> let instance = Object.create(o);
> instance.constructor(/* constructor args */)
>
> This assumes that the new instance will inherit "constructor" from its prototype chain (possibly all the way to Object.prototype.constructor (.i.e. Object).
> If you are careful to always code your constructors to return this, you can shorten it to:
>
> let instance  = Object.create(o).constructor(/* constructor args */);
>
> As I think I have talked about in the past.  For ES.next I think we should extend the semantics of new to be approximately:
>
> function ESNewOperator( rhs, args) {
>    if (rhs has [[Constructor]] ) return rhs.[[Constructor]].apply(undefined,args);
>    let instance = Object.create(rhs);
>    instance.constructor(...args);
>    return instance;
> }
> ( a few additional error conditions need to be added)
>
> This allows the new operator  to make sense (and work in an internally interoperable manner) for both prototypical and classical inheritance
>
> For example:
>
> let proto = {
>    depth: 0;
>    constructor: function() {this.depth +=  1};  /* get parent's depth, increment it, and store as own property of instance */
> }
>
> let lev1 = new proto;
> let lev2 = new lev1;
> let lev3 = new lev2;
I love this!

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

Cameron McCormack-4
In reply to this post by Allen Wirfs-Brock
On 24/09/11 8:35 AM, Allen Wirfs-Brock wrote:
> Regarding, WebIDL.  It seems to me, that it just needs an extended attribute to specifies which attributes are instance attributes rather than prototype attributes.

I think it only makes sense to have IDL attributes correspond to
properties on the instance itself if the property can be a data
property, and that if it can be modelled with a data property then it
needs to have no special behaviour when being assigned to (no type
coercions due to IDL, no other behaviour), unless we want to require JS
implementations to use proxies for these objects.

I don't think many attributes in Web APIs fall into this category.
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

David Bruant-4
Le 11/10/2011 05:48, Cameron McCormack a écrit :

> On 24/09/11 8:35 AM, Allen Wirfs-Brock wrote:
>> Regarding, WebIDL.  It seems to me, that it just needs an extended
>> attribute to specifies which attributes are instance attributes
>> rather than prototype attributes.
>
> I think it only makes sense to have IDL attributes correspond to
> properties on the instance itself if the property can be a data
> property, and that if it can be modelled with a data property then it
> needs to have no special behaviour when being assigned to (no type
> coercions due to IDL, no other behaviour)
Oh true! Current WebIDL 4.5.5 Attribute, for the setter, step 6 "Let
idlValue be the result of converting V to an IDL value.". So, DOM
attributes are typed and the typing is enforced by their ECMAScript
representation.

> unless we want to require JS implementations to use proxies for these
> objects.
Indeed. I hadn't noticed the type enforcement. I take back all what I
said about DOM attributes being data property. A setter with type
enforcement sounds like a better idea than proxies returning data
descriptor.

It gives me an idea for a proxy library which would be to pass a custom
field in a data descriptor indicating the type. The proxy would enforce
the type under the hood and either coerce silently or throw if the type
is incorrect.

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

Mark S. Miller-2
On Tue, Oct 11, 2011 at 11:43 AM, David Bruant <[hidden email]> wrote:
It gives me an idea for a proxy library which would be to pass a custom field in a data descriptor indicating the type. The proxy would enforce the type under the hood and either coerce silently or throw if the type is incorrect.


That's a cool idea, and a good way to experiment with possible future (post ES6) direct representation of type-constrained (or guard constrained) properties. 


--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

Tom Van Cutsem-3
2011/10/11 Mark S. Miller <[hidden email]>
On Tue, Oct 11, 2011 at 11:43 AM, David Bruant <[hidden email]> wrote:
It gives me an idea for a proxy library which would be to pass a custom field in a data descriptor indicating the type. The proxy would enforce the type under the hood and either coerce silently or throw if the type is incorrect.


That's a cool idea, and a good way to experiment with possible future (post ES6) direct representation of type-constrained (or guard constrained) properties.

Indeed, and another argument in favor of copying over non-standard property attributes to normalized property descriptors crossing the defineProperty / getOwnPropertyDescriptor trap boundaries.

Cheers,
Tom

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Instance constructors

Brendan Eich-3
In reply to this post by David Bruant-4
On Oct 11, 2011, at 5:43 AM, David Bruant wrote:

> It gives me an idea for a proxy library which would be to pass a custom field in a data descriptor indicating the type. The proxy would enforce the type under the hood and either coerce silently or throw if the type is incorrect.

The original DOM in Netscape 2 did this -- native data structures had proxy-like wrappers with get and set traps, to use Proxy terminology. The Netscape layout engine built these structures quickly and during progressive rendering (remember dial-up?). I did not want to reify JS objects for each eagerly, so used proxy-like wrappers created on demand. The source of truth was in the C (no portable C++ back then) data structures, so I needed get and set traps. This was before accessor properties, so the resulting "DOM attributes" looked like data properties, but did not behave as if they were data properties.

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