class prototype object vs class instance properties
On 17/08/07, Garrett Smith <dhtmlkitchen at gmail.com> wrote:
What is the difference between a class's prototype object and it's instance properties?
Prototype properties are fallbacks if the property does not exist on the instance.
class A { var x : uint = 10; // instance property. prototype var x : uint = 20; // another instance property in the prototype chain. }
class B extends A { }
My understanding is that the result would be:
new B().x; // result is 20.
What would be the benefit of a class having a prototype over 9instance properties/methods?
Prototype properties can be shadowed by instance properties without being changed, prototype properties are fallbacks if the instance property does not exist, and prototype properties are not part of the actual instance, so can be used as memory footprint reduction if one has lots of instances that don't need separate values for that instance property.
liorean wrote:
On 8/18/07, Brendan Eich <brendan at mozilla.org> wrote:
On Aug 18, 2007, at 10:13 AM, Garrett wrote:
liorean wrote:
What would be the benefit of a class having a prototype over 9instance properties/methods?
Prototype properties can be shadowed by instance properties without being changed, prototype properties are fallbacks if the instance property does not exist, and prototype properties are not part of the actual instance, so can be used as memory footprint reduction if one has lots of instances that don't need separate values for that instance property.
That's pretty much how es3 works, then.
In fact the reference implementation at ecmascript.org uses ES4 class definitions to create the built-in classes from ES1-3 (Object, Date, etc.). A few fine points:
In |dynamic class Object {...}|, the |dynamic| keyword is required if you want the class's instances, not just its prototype, to allow ad- hoc properties to be set on them. So indeed, |Object| is a dynamic class in the reference implementation.
I understand that.
In |class C { var x; }; c = new C; c.x = 42| and |dynamic class D { prototype var x; }; d = new D; d.x = 42| both c and d wind up with an x property having value 42. But c.x is a "fixture" -- it can't be deleted, and if it has a type annotation, that type constraint can't be altered. Whereas d.x is just an ad-hoc property on a dynamic class's instance, which happens to shadow prototype var x, but has no type relation to that prototype property.
A function definition inside a class C's body |class C { function m ():void {...} ...}| creates a method fixture named m, which has a function structural type |function (this:C):void| and which can't be deleted or overwritten.
So classes, fields (var in class), and methods (function in class) respectively provide objects with private members where the instances cannot be extended, properties that can't be deleted or have their type annotations violated, and receiver-based method dispatch (again with existence and type guarantees). These can be emulated in ES3 in several ways, at some cost in clarity and runtime efficiency.
I understand that.
But these methods are also bound, right?
In current coding conventions, many programmers (including myself) like to have the constructor's prototype assigment in one place with an object literal.
function A { // instance props. this.init(); } A.prototype = { Events : { // Enum would be nice. "open" : "open" }
,init : function init() { } };
This "objec tliteral"styleis not congruent to the prototype being a special instance (as in ES3 and 4 built-ins, with Date.prototype having value NaN, et c) . The above code style is clear and easy to read. You have the constructor, then the prototype.
It would be nice to have a prototype block, like:
class A {
init : void = function init() prototype {
}
function A () {
}
}
I am not sure if the with(prototype) { ... } would be suitable for that approach. I think with statements should not be encouraged.
I'm also confused on the syntax for function return type.
ES4:
class P { f:Void= function f() {print('fff');}} [function Function]
new P().f() [stack] [] ERROR EvalError: uncaught exception: ReferenceError: unresolved object reference {multiname: [ns public '']::f } (near builtins/Error.es:83.47-83.47)
On Aug 18, 2007, at 1:51 PM, Garrett Smith wrote:
But these methods are also bound, right?
Yes, good point -- I left out that further detail. |this| always
refers in a method to the instance from which the method was called
or extracted.
In current coding conventions, many programmers (including myself) like to have the constructor's prototype assigment in one place with an object literal.
Yeah, I like and use that convention too.
This "object literal"styleis not congruent to the prototype being a special instance (as in ES3 and 4 built-ins, with Date.prototype having value NaN, et c) . The above code style is clear and easy to read. You have the constructor, then the prototype.
It would be nice to have a prototype block, like:
class A {
init : void = function init() prototype {
}
This is something proposed ages ago by Waldemar Horwat (then at
Netscape) for ES4 -- any time you have
prototype function m1(...) {...} prototype function m2(...) {...} prototype function m3(...) {...}
in some ES4 drafts waldemar wrote, you could instead say
prototype { function m1(...) {...} function m2(...) {...} function m3(...) {...} }
Waldemar's proposal allowed this for any kind of "attribute"
qualifying a definition, including a namespace IIRC.
I'll bring this up at the next meeting, since you are quite right
that the current builtins in the reference implementation are chatty.
I am not sure if the with(prototype) { ... } would be suitable for that approach. I think with statements should not be encouraged.
Right, |with| is not suitable here -- it won't change the scope in
which functions and vars are bound in a class any more than it would
elsewhere (as it does not in ES1-3). Also, it is being deprecated
(there's a reformed with that can be used if you're retrofitting, or
if you like with and want to use it without scope ambiguity).
I'm also confused on the syntax for function return type.
ES4:
class P { f:Void= function f() {print('fff');}} [function Function]
new P().f() [stack] [] ERROR EvalError: uncaught exception: ReferenceError: unresolved object reference {multiname: [ns public '']::f } (near builtins/Error.es:83.47-83.47)
You didn't define a method f in class P. Look:
class P { f:Void= function f() {print('fff');}} [function Function]
Void [function Function]
Void()
fff
the f: is a section label, like private: or public:. The Void name is
unbound and on the left-hand side of assignment (=) in class P's
initialization code, so that's an assignment expression-statement
executed once when the class is processed. Per the usual rules, the
assignment binds a global property named 'Void'.
I don't know where you saw an example that looked anything like that.
In the mail I wrote, to which you are replying here, I showed a void
method:
class C { function m():void {...} ...}
The return type annotation, which is optional, goes after the
function formal parameter list, and starts with : as for all type
annotations. The use of |void| here shows a special case: 'void' is
not a type name, it means instead that the function cannot contain
'return expr;' statements, only 'return;' statements and falling-off-
the-end-without-return. There is no 'Void' type in ES4. The type of
the undefined value is a type named undefined (available only in type
expression contexts), same as for null/null.
This "object literal"styleis not congruent to the prototype being a special instance (as in ES3 and 4 built-ins, with Date.prototype having value NaN, et c) . The above code style is clear and easy to read. You have the constructor, then the prototype.
It would be nice to have a prototype block, like:
class A {
init : void = function init() prototype {
}
This is something proposed ages ago by Waldemar Horwat (then at Netscape) for ES4 -- any time you have
prototype function m1(...) {...} prototype function m2(...) {...} prototype function m3(...) {...}
in some ES4 drafts waldemar wrote, you could instead say
prototype { function m1(...) {...} function m2(...) {...} function m3(...) {...} }
Waldemar's proposal allowed this for any kind of "attribute" qualifying a definition, including a namespace IIRC.
That's right.
I'll bring this up at the next meeting, since you are quite right that the current builtins in the reference implementation are chatty.
ActionScript will have something like this soon in its program configuration feature. It is described here:
proposals:program_configuration
The meaning is slightly different, but maybe not incompatible. In the above proposal, a configuration expression turns on or off a block of code, including any embedded definitions. If non-configuration attributes where used on a block they could be applied to relevant definitions. Perhaps it should be an error to put definitions in a block whose attributes don't apply.
What is the difference between a class's prototype object and it's instance properties?
class A { var x : uint = 10; // instance property. prototype var x : uint = 20; // another instance property in the prototype chain. }
class B extends A { }
My understanding is that the result would be:
new B().x; // result is 20.
What would be the benefit of a class having a prototype over 9instance properties/methods?