Re: ES4 draft: Object
That sore thumb propertyIsEnumerable. propertyIsEnumerable, as a setter, sets the DontEnum flag for the object's own property. A value of 'false' makes the prop not show up in - for in. propertyIsEnumerable, as a getter, gets the value of the negation of the DontEnum flag, and does not check the prototype chain. Has nothing to do with whether or not the object shows up in - for in. The addition adds a non-orthogonal aspect, apparently to add some needed functionality. This unituitive behavior is especially problematic to amateur, or unskilled developers. The following code example from google demonstrates this to be true: http://doctype.googlecode.com/svn/trunk/goog/base.js if (Object.prototype.propertyIsEnumerable) { /** * Safe way to test whether a property is enumarable. It allows testing * for enumarable on objects where 'propertyIsEnumerable' is overridden or * does not exist (like DOM nodes in IE). * @param {Object} object The object to test if the property is enumerable. * @param {string} propName The property name to check for. * @return {boolean} True if the property is enumarable. * @private */ goog.propertyIsEnumerable_ = function(object, propName) { return Object.prototype.propertyIsEnumerable.call(object, propName); }; } else { /** * Safe way to test whether a property is enumarable. It allows testing * for enumarable on objects where 'propertyIsEnumerable' is overridden or * does not exist (like DOM nodes in IE). * @param {Object} object The object to test if the property is enumerable. * @param {string} propName The property name to check for. * @return {boolean} True if the property is enumarable. * @private */ goog.propertyIsEnumerable_ = function(object, propName) { // KJS in Safari 2 is not ECMAScript compatible and lacks crucial methods // such as propertyIsEnumerable. We therefore use a workaround. // Does anyone know a more efficient work around? / BROKEN: this approach checks the prototype chain with - if(propName in object) // (gsmith) if (propName in object) { for (var key in object) { if (key == propName) { return true; } } } return false; }; } Because we can see that the author appears to have made the assumption that propertyIsEnumerable would check the prototype chain. This is a perfectly natural assumption. What is more confusing is that with the new proposal: function X(){} X.prototype = { p : true; }; var x = new x; x.propertyIsEnumerable('p'); // false, p is in the [[Prototype]] for(var prop in x) alert(prop); // alerts 'p' Garrett 2008/3/17 Lars Hansen [EMAIL PROTECTED]: Draft 3 of the spec for the Object class. Changelog near the beginning. (Notably this version includes draft code for __createProperty__.) --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
[Coming late to the party] On 2008-03-13, at 12:47 EDT, Lars Hansen wrote: function __createProperty__(name:EnumerableId, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void If I did my math right there are 8 possible flag combinations, but only 6 make sense. Why not a single parameter that is a member of an enumeration? Maybe the enumeration values could be named mnemonically to match the ES4 declarative syntax? ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object initializers
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Lars Hansen Sent: 7. april 2008 16:20 To: es4-discuss@mozilla.org Subject: RE: ES4 draft: Object initializers Here is the second draft, which incorporates most things discussed so far. Changelog near the beginning, with an OPEN ISSUES section. One facility that was introduced in this draft copies the type tags of 'const' and 'var' attributed properties into the type of the object, for ease of use. As a consequence, this test is true: { const x: foo } is { x: string } I am going to remove that facility again because it violates the explicit is better than implicit principle. IMO the programmer should state her intent: { const x: foo } : { x: string } Type definitions help make this somewhat less wordy. And with or without the type annotation x would still be a read-only fixture, as desired, but the type of the x property would be *, not string. (It's easy to say that when the literals are simple then the types are obvious, but once they involve more complicated expressions I'm guessing the gains are illusory.) --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object initializers
-Original Message- From: Mark S. Miller [mailto:[EMAIL PROTECTED] Sent: 8. april 2008 15:38 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object initializers On Tue, Apr 8, 2008 at 12:20 PM, Lars Hansen [EMAIL PROTECTED] wrote: One facility that was introduced in this draft copies the type tags of 'const' and 'var' attributed properties into the type of the object, for ease of use. As a consequence, this test is true: I don't understand how this could work for var. The type is introduced on the fixture based on the initial value; subsequent values will be constrained to be of that type. In terms of Draft 2, obj = { var x: foo } // same as { x:foo } : { x:string } obj.x = bar // ok obj.x = 37 // not ok { const x: foo } is { x: string } I am going to remove that facility again because it violates the explicit is better than implicit principle. IMO the programmer should state her intent: { const x: foo } : { x: string } A possible counter-argument is that the type of foo is string rather than *. We don't make the programmer write foo :string in order to get the right type. It's true, we don't. But object initializers evaluate to new compound objects every time, not to immutable values that are ===, so I'm skeptical about the analogy. The type of an ES3 object initializer is 'Object' (not *). And if all the constituents of the initializer are literal expressions it's easy enough to see what's going on. But not if the constituents are not literal expressions. (It's easy to say that when the literals are simple then the types are obvious, but once they involve more complicated expressions I'm guessing the gains are illusory.) That's not clear to me. The cases that come to mind compose well: { const x: { const y: bar } } has type { x: { y: string }} I'm more concerned about cases like this: { const x: f() } which are quite opaque and where the object will have a type that depends on the value returned by f, possibly a different type every time the initializer is evaluated. It's not the unbounded number of types that worries me but the fact that the type of that expression is at the mercy of f. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object initializers
var (outside of eval, an ES1 flaw) means DontDelete. /be On Apr 7, 2008, at 1:50 PM, Mark S. Miller wrote: On Mon, Apr 7, 2008 at 10:21 AM, Lars Hansen [EMAIL PROTECTED] wrote: IMO it ought to be possible to use 'var' in those same ways but we didn't discuss that much (if at all). I don't understand. What would it mean? -- Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object initializers
On Mon, Apr 7, 2008 at 2:47 PM, Brendan Eich [EMAIL PROTECTED] wrote: var (outside of eval, an ES1 flaw) means DontDelete. Excellent! -- Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object initializers
I can ask `o[f] !== undefined` to determine if a defined property named `f` exists in `o`, whether `f` is a fixture or not, correct? If I only have `o`, is there a way for me to detect whether `f` is implemented as a getter in `o`, or is that completely invisible to me? On 2008-03-20, at 19:42 EDT, Lars Hansen wrote: I've attempted to sum up everything we have decided about object initializers (aka object literals). A short draft spec is included. Comments welcome from everyone, especially from ES4 WG members who might remember about things I've forgotten, or correct misunderstandings. --lars object-literals.html___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object initializers
o[f] !== undefined does not determine fixtureness, only whether f's there. The way to ask about fixtureness is by using a type, I think the following should work regardless of the actual type of x in o: o is { x: * } If you want to use a variable value f and not a constant name x then (perversely) I believe the following should work: o is let (t = gensym()) global.eval(type + t + = { + f + :* }; return + t, 4) but you have to write your own gensym. To my knowledge there is no way to ask whether something is a getter or setter. That said, the draft of the reflection API is not yet out and it seems like the kind of thing that it should possibly be able to reveal. (The reflection API should be able to answer the previous two questions too.) --lars -Original Message- From: P T Withington [mailto:[EMAIL PROTECTED] On Behalf Of P T Withington Sent: 21. mars 2008 05:15 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object initializers I can ask `o[f] !== undefined` to determine if a defined property named `f` exists in `o`, whether `f` is a fixture or not, correct? If I only have `o`, is there a way for me to detect whether `f` is implemented as a getter in `o`, or is that completely invisible to me? On 2008-03-20, at 19:42 EDT, Lars Hansen wrote: I've attempted to sum up everything we have decided about object initializers (aka object literals). A short draft spec is included. Comments welcome from everyone, especially from ES4 WG members who might remember about things I've forgotten, or correct misunderstandings. --lars object-literals.html___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object initializers
A bug: repeated fields are also disallowed if the object initializer has a type annotation. In summary, only object initializers that look like ES3 initializers are allowed to have repeated fields (for backward compatibility). --lars -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Lars Hansen Sent: 20. mars 2008 16:43 To: es4-discuss@mozilla.org Subject: ES4 draft: Object initializers I've attempted to sum up everything we have decided about object initializers (aka object literals). A short draft spec is included. Comments welcome from everyone, especially from ES4 WG members who might remember about things I've forgotten, or correct misunderstandings. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
ES4 draft: Object initializers
I've attempted to sum up everything we have decided about object initializers (aka object literals). A short draft spec is included. Comments welcome from everyone, especially from ES4 WG members who might remember about things I've forgotten, or correct misunderstandings. --lars Title: Object literals Object initializer syntax NAME: "Object initializer syntax" FILE: spec/language/object-literals.html CATEGORY: Expressions (E262-3 chapter 11) SOURCES:ES3; REFERENCES [1]-[6] SPEC AUTHOR:Lars DRAFT STATUS: DRAFT 1 - 2008-03-20 REVIEWED AGAINST ES3: YES REVIEWED AGAINST ERRATA:YES REVIEWED AGAINST BASE DOC: YES REVIEWED AGAINST PROPOSALS: YES REVIEWED AGAINST CODE: NO REVIEWED AGAINST TICKETS: YES IMPLEMENTATION STATUS: ? TEST CASE STATUS: ? REFERENCES [1] ES4 base document [2] Ticket #164 [3] Ticket #165 [4] Ticket #219 [5] Ticket #319 [6] Bug fixes proposal, item about comma at the end of the field list Synopsis This note tries to pin down all that has been decided about object initializer syntax. A brief rationale is attached at the end. Primary syntax In its general form an object initializer is comprised of a brace-delimited comma-separated list of fields with the last field optionally followed by a comma, followed by an optional type annotation (which has to be a structural record type). ObjInit ::= "{" ( ( Field "," )* Field ","? )? "}" [ ":" RecType ] Field ::= FieldName ":" AssignmentExpression | "var" FieldName ":" AssignmentExpression | "const" FieldName ":" AssignmentExpression | "get" FieldName "(" ")" [":" Type] FunctionBody | "set" FieldName "(" Param ")" [ ":" "void" ] FunctionBody FieldName ::= AnyIdentifier | AnyIdentifier "::" AnyIdentifier | LiteralString | LiteralNumber AnyIdentifier ::= Identifier | ReservedWord The FunctionBody of a getter can be a block or an _expression_. The FunctionBody of a setter can only be a block (until we decide that ": void" on an _expression_ closure transforms the value computed to void before "returning"). It is possible to have a getter without a setter and a setter without a getter. A compatible getter or setter will be generated for the missing method. The generated setter method receives a value and discards it silently (this corresponds with the view that writing to ReadOnly properties fails silently). The generated getter method throws a ReferenceError. Fields names may be repeated only if none of the instances of a name are qualified by var, const, get, or set. Construction Unlike the case in ES3, the program can't shadow the binding for Object in order to invoke an alternative object constructor for object initializers. Secondary syntax Suppose T is a structural record type: type T = { x: int, y: double } Then the new operator can be used as follows: new T(10, 2.5) The meaning of this is precisely: { x: 10, y: 2.5 } : T There must be as many arguments to new as there are fields in T. The initializers are matched with fields by the order in which they appear. Semantics of subphrases Types and fixtures If a property name in the record type that annotates the literal matches a field name in the literal then the field is a fixture (as opposed to a dynamic property) and the type of the fixture is the type of the property given in the record type. The following makes x a fixture and gives it the type int: { x: 10 } : { x: int } The type of the value must be of the type of the field, or must be convertible to the type of the field. If a property name in the record type matches a field name that is a getter and/or a setter then: either the getter has no return type annotation (in which case the type from the record type will be applied to the getter) or the return type must be equal to the type present for the property in the record type; either the setter has no parameter type annotation (in which case the type from the record type will be applied to the parameter) or the parameter type must be equal to the type present for the property in the record type; and following resolution of the previous two points, the return type of the (generated) getter, the parameter type of the (generated) setter, and the type in the record type must all be equal. Fields may be present in the field list that are not present in the type, but not vice versa. I.e., the following is legal: x = { x: 10, y: 20, z: 30 } : { x: int, y: int } A field that does not have a matching explicit type annotation in the record type is dynamic, which is to say it is deletable. Note in particular that this applies to
Re: ES4 draft: Object initializers
On 21/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: I've attempted to sum up everything we have decided about object initializers (aka object literals). A short draft spec is included. Comments welcome from everyone, especially from ES4 WG members who might remember about things I've forgotten, or correct misunderstandings. Just a few ideas, I think there's a few declarative features I'd like to see added: - I'd *really* like to see some declarative syntax for setting {DontEnum} flag on properties in object initialisers. - A declarative way to set catch-alls. - A declarative way to set the [[Call]] property. - And maybe declarative way to set the [[Prototype]] property. (This would of course be const.) var a={ dontenum toString: function()'[object customObj]' }, b={ [[Prototype]]: a, [[Call]]: function()..., get *: function(propname)..., set *: function(propname, value)..., ... }; The brackets for syntax would from what I can tell work here, since they are syntax errors in ES3. Or using some double keyword syntax I guess. -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object initializers
On 3/20/08, Lars Hansen [EMAIL PROTECTED] wrote: Thanks for pointing some of these out, Brendan did the same. This is already legal to define catch-alls: { var meta::get: function () { ... } } Is there a more recent version of the grammar than the docs at http://wiki.ecmascript.org/doku.php?id=proposals:normative_grammar ? This syntax isn't legal according to the grammar there, nor is it recognized by the RI. -Jon ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
Draft 3 of the spec for the Object class. Changelog near the beginning. (Notably this version includes draft code for __createProperty__.) --lars Title: The class "Object" The class Object NAME: "The class 'Object'" FILE: spec/library/Object.html CATEGORY: Pre-defined classes (E262-3 Chapter 15) SOURCES:REFERENCES [1], [2] SPEC AUTHOR:Lars DRAFT STATUS: DRAFT 3 - 2008-03-14 REVIEWED AGAINST ES3: YES REVIEWED AGAINST ERRATA:YES REVIEWED AGAINST BASE DOC: YES REVIEWED AGAINST PROPOSALS: YES REVIEWED AGAINST CODE: YES IMPLEMENTATION STATUS: ES4RI TEST CASE STATUS: ? CHANGES SINCE DRAFT 2 (2008-03-10) * Removed a "note" below * Fixed the spec for Object.prototype.toString (there needs to be a space preceding the class name) * Removed the optional second argument on 'propertyIsEnumerable' * Added the method __createProperty__ CHANGES SINCE DRAFT 1 (2008-03-05) * More elaborate status block above * Prototype methods do not delegate to the corresponding intrinsic methods, but to shared private methods that are also called by the intrinsic method. In this fashion, prototype method behavior is invariant of subclassing * Introduction of a specification-only protocol helper::getClassName for overriding class names for ES3 compatibility NOTES * The use of 'Private' instead of 'private' below is a workaround for a bug in the reference implementation (#368) REFERENCES [1] http:wiki.ecmascript.org/doku.php?id=proposals:enumerability [2] builtins/Name.es in the ES4 RI The class Object is a dynamic non-final class that does not subclass any other objects: it is the root of the class hierarchy. All values in ECMAScript except undefined and null are instances of the class Object or one of its subclasses. NOTE Host objects may not be instances of Object or its subclasses, but must to some extent behave as if they are (see Host objects). Synopsis The class Object provides this interface: public dynamic class Object { public function Object(value=undefined) static meta function invoke(value=undefined) static public const length = 1 intrinsic function toString() : string intrinsic function toLocaleString() : string intrinsic function valueOf() : Object intrinsic function hasOwnProperty(name: EnumerableId): boolean intrinsic function isPrototypeOf(value): boolean intrinsic function propertyIsEnumerable(name: EnumerableId): boolean intrinsic function __createProperty__(name: EnumerableId, value, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void } The Object prototype object provides these direct properties: toString: function () toLocaleString: function () valueOf: function () hasOwnProperty: function (name) isPrototypeOf:function (value) propertyIsEnumerable: function (name) __createProperty__: function (name, value, dontEnum=undefined, dontDelete=undefined, readOnly=undefined) The Object prototype object is itself an instance of the class Object, with the exception that the value of its [[Prototype]] property is null. Methods on the Object class object newObject(value=) Description When the Object constructor is called with an argument value (defaulting to undefined) as part of a new _expression_, it transforms the value to an object in a way that depends on the type of value. Returns The Object constructor returns an object (an instance of Object or one of its subclasses, or a host object). NOTE The Object constructor is the only constructor function defined on a class in the language whose result may be a value of a different class than the one in which the constructor is defined. Implementation The Object constructor can't be expressed as a regular ECMAScript constructor. Instead it is presented below as a helper function makeObject that the ECMAScript implementation will invoke when it evaluates new Object. The helper function makeObject only is invoked on native ECMAScript values. If new Object is evaluated on a host object, then actions are taken and a result is returned in an implementation dependent manner that may depend on the host object. helper function makeObject(value=undefined) { switch type (value) { case (s: string) { return new String(s); } case (b: boolean) { return new Boolean(b); } case (n: (int|uint|double|decimal)) { return new Number(n); } case (x: (null|undefined)) { return magic::createObject(); } case (o: Object) { return o; } } } Object(value=) Description When the Object class object is called as a function with zero or one arguments it performs a type conversion. Returns It returns the converted
Re: ES4 draft: Object
Brendan Eich wrote: If we end up making all namespaced properties non-enumerable, then we may want a property iterator that returns the names of all properties in a given object. Even if this is not in the standard, it's likely to be an extension. Or it could be added in the future. Absolutely. In fact, I thought there was already an iterator that yields all properties regardless of enumerability, just that this iterator would not be the default iterator for objects. If it's not in ES4, it should definitely be there because it's essential for those that want to customize enumerability. The question of whether ES3+4 mixtures might not want enumerable ES3 properties to appear to be in a predefined-in-ES4 namespace seems to me worth considering, at the limit as a future-proofing step. What do you mean by ES3+4 mixture - how would you tell that one part is ES3 and another part ES4, or how a program is pure ES4? -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Peter Hall wrote: The latter. It is weird, I agree. But the enumerator can easily be customized, so I want the default enumerator be as non-magical as possible - and therefore, as simple as possible. In fact, I'm a bit bothered that propertyIsEnumerable is a method of Object yet can be rendered useless when changing the enumerator - along this line of reasoning, one would think that such a specific method shouldn't be a method of Object at all, but rather the enumerator itself. So how would you go about enumerating the properties of an arbitrary dynamic object, whose properties could be in namespaces? I thought there was an iterator that would enumerate all properties regardless of enumerability (including those in other namespaces), but apparently not. There should be such an iterator though. Yeah, I vaguely remember some discussion concerning multiple namespaces per property a long time ago (maybe a year ago). It was rejected probably due to complexity. Not being able to combine them effectively makes many of the initial proposal's use-cases useless, because two use-cases may arise simultaneously when integrating two codebases, and be irreparably conflicting. Peter What initial proposal are you talking about? -Yuh-Ruey ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
the frequency of use). Thus on Object.prototype and as an intrinsic propety on Object instances: function __createProperty__(name:EnumerableId, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void I thought that this only made sense in conjunction with Neil's suggestion of providing the value at the same time. If you create a readonly property, how are you supposed to set the value otherwise? Shouldn't it be: function __createProperty__(name:EnumerableId, value, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void And if readOnly implied dontDelete, I would have guessed readOnly to be a little more frequent than dontDelete, but of course that is just a guess. Kris ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Yuh-Ruey Chen wrote: Brendan Eich wrote: If we end up making all namespaced properties non-enumerable, then we may want a property iterator that returns the names of all properties in a given object. Even if this is not in the standard, it's likely to be an extension. Or it could be added in the future. Absolutely. In fact, I thought there was already an iterator that yields all properties regardless of enumerability, just that this iterator would not be the default iterator for objects. If it's not in ES4, it should definitely be there because it's essential for those that want to customize enumerability. As was discussed before, the language cannot have such an iterator. Were this iterator to exist, an attacker could use it to discover hidden properties of objects, get access to private and other restricted namespaces, alter private state, and break through abstraction barriers. Waldemar ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
Is there enough value in complicating matters by adding the ability to set dontDelete and readOnly? You can create non-deletable properties by using a class or record type, and you can create read-only properties by adding a get function without a corresponding set... Are there any use cases where these solutions won't cover it? Peter ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: Controlling DontEnum (was: ES4 draft: Object)
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Peter Hall Sent: 13. mars 2008 12:38 To: Lars Hansen Cc: Kris Zyp; es4-discuss@mozilla.org Subject: Re: Controlling DontEnum (was: ES4 draft: Object) Is there enough value in complicating matters by adding the ability to set dontDelete and readOnly? You can create non-deletable properties by using a class or record type, and you can create read-only properties by adding a get function without a corresponding set... Are there any use cases where these solutions won't cover it? Depends on your point of view. I wrote a paper on evolutionary programming in ES4 (available from ecmascript.org), which demonstrates a progression from ES3 style code to ES4 style code with various stops along the way. One of the holes in that story is that it's not possible to make the properties introduced in a function-style constructor anything but enumerable, deletable, and writable: function Server(host) { this.host = host this.database = [] } Both these fields are supposed to be constant, and there's no reason for them to be enumerable. The paper shows how you can use a user-defined namespace to make them inaccessible (non-public namespaced properties are not enumerated, and if the namespace is hidden from client code -- not always easy -- then the field can't be accessed or deleted), but it's clearly a bit of a hack in that it is a consequence of other design choices in the language. The direct approach would set the properties explicitly: function Server(host) { this.__createProperty__(host, host, true, true, true); this.__createProperty__(database, [], true, true, true); } So this is a use case if you believe that relatively fine-grained evolution from ES3 style to ES4 style is a feature of the language. (I do.) There are declarative ways of solving the problem -- essentially annotating the function, saying this is a constructor function and the fields named such and so are going to have these and those attributes, but they add yet more features to an already fairly feature-laden language. (One proposal goes like this: constructor function Server(host) : { const host: string, const database: array } { this.host = host this.database = [] } and it's not all that heavyweight, but it's a new, ad hoc feature all the same.) I'm mostly agnostic about __createProperty__ being able to set DontDelete and ReadOnly; DontEnum is the really important one. At the same time, it seems silly not to just solve the general problem when we have a chance. Just because you can't enumerate a property doesn't mean that you -- or a library you import -- can't accidentally -- or maliciously -- overwrite it. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
set dontDelete and readOnly? You can create non-deletable properties by using a class or record type They can't be added after an object is created. and you can create read-only properties by adding a get function without a corresponding set... Unless behavior is different than ES3, setters (and lack thereof) are not dontDelete, therefore still easily mutated: obj = {get foo() { return 'hi' }} Object foo=hi obj.foo hi delete obj.foo true obj.foo = 'goodbye' goodbye obj.foo goodbye ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On 13/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: Since our method is creating a new property and not setting one, I suggest __createProperty__ as the most appropriate name, so I'm going to use that below. Sounds perfectly reasonable to me. I still think it may be right that properties in non-public namespaces should not be enumerated, but I also think that's orthogonal to the discussion that's going on here, about dynamic properties and their attributes. We've pretty much decided (ticket #233 has some of the discussion) that for future compatibility there ought to be a difference between fixture properties and DontDelete dynamic properties. So dynamic properties have at least one attribute bit like they do in ES3 (for deletability). Consequently, they might as well have all the ES3 bits: for enumerability and writability. For ES4, shouldn't this function also take a type binding? Ergo, let's assume that we are not finessing more than we have to, and dynamic properties have all these attribute bits. I don't know why __createProperty__ should not be able to set all of these. Neither can I. (They're not independent, ReadOnly implies DontDelete.) __createProperty__ should throw an exception (TypeError?) if the property already exists on the object or would shadow a ReadOnly property, a la [[CanPut]], or if the object is not dynamic. It should probably throw an exception if its arguments are not consistent (ReadOnly !DontDelete). If ReadOnly is specified, is there even a reason to look at DontDelete? Pesonally I like the strings approach, but the only interface among these four that has good compile-time checking is the first one, so I'm going to propose that we use that one, with dontEnum as the first flag, dontDelete as the second, and readOnly as the third (based on a guess about the frequency of use). Thus on Object.prototype and as an intrinsic propety on Object instances: function __createProperty__(name:EnumerableId, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void ReadOnly would need to be instanciated at the same time, no? And you probably want to be able to specify a type binding for ES4. * The above does not preclude complementary declarative mechanisms in ES4 (but not in ES3.1 obviously) Good to hear, because I still want to see something that can be used in object literals and property declarations. -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On Mar 13, 2008, at 11:47 AM, Lars Hansen wrote: function __createProperty__(name:EnumerableId, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void I like where this is going. May I (in addition to Kris's suggestion for adding a value parameter) kindly nit on the parameter names? function __createProperty__(name:EnumerableId, value:*, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void Or some reasonable variant therein? I have no strong opinions on the form the parameters eventually take, but trying to parse what dontenum=false means tends to give me headaches. ;) ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: Controlling DontEnum (was: ES4 draft: Object)
-Original Message- From: Neil Mix [mailto:[EMAIL PROTECTED] Sent: 13. mars 2008 14:47 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: Controlling DontEnum (was: ES4 draft: Object) On Mar 13, 2008, at 11:47 AM, Lars Hansen wrote: function __createProperty__(name:EnumerableId, dontEnum:boolean=false, dontDelete:boolean=false, readOnly:boolean=false): void I like where this is going. May I (in addition to Kris's suggestion for adding a value parameter) kindly nit on the parameter names? function __createProperty__(name:EnumerableId, value:*, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void Or some reasonable variant therein? I have no strong opinions on the form the parameters eventually take, but trying to parse what dontenum=false means tends to give me headaches. ;) Well, it had to come up at some point ;) I suspect what you're proposing is the better UI. Obviously JS1/ES3 shows a bias for enumerable, removable, writable properties -- the attribute bits flag exceptions from the general rule. The more general design has attribute bits that simply control those property aspects, and the less biased names feel like an improvement. Brendan, opinions? --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On Mar 13, 2008, at 2:07 PM, Lars Hansen wrote: -Original Message- From: Neil Mix [mailto:[EMAIL PROTECTED] function __createProperty__(name:EnumerableId, value:*, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void Or some reasonable variant therein? I have no strong opinions on the form the parameters eventually take, but trying to parse what dontenum=false means tends to give me headaches. ;) Well, it had to come up at some point ;) I suspect what you're proposing is the better UI. Obviously JS1/ES3 shows a bias for enumerable, removable, writable properties -- the attribute bits flag exceptions from the general rule. The more general design has attribute bits that simply control those property aspects, and the less biased names feel like an improvement. Brendan, opinions? Neil's names are much better. For the record, I didn't come up with DontDelete and DontEnum in ES1 daze. SpiderMonkey internally uses PERMANENT for the former and ENUMERATE for the inverse of the latter (since the native-biased API finds callers wanting enumerable pre- defined properties to be the exception). /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
FWIW, AS3, which doesn't have iterators, enumerates only the expando properties of an object. This was in part because we didn't have (qualified) name objects that could be enumerated, and in part because of it being complicated to determine the set of names that could be safely exposed (e.g. all the names in open namespaces, all the public names regardless of their current visibility, etc). IOW, we punted. Jd On 3/13/08 11:29 AM, Waldemar Horwat wrote: Yuh-Ruey Chen wrote: Brendan Eich wrote: If we end up making all namespaced properties non-enumerable, then we may want a property iterator that returns the names of all properties in a given object. Even if this is not in the standard, it's likely to be an extension. Or it could be added in the future. Absolutely. In fact, I thought there was already an iterator that yields all properties regardless of enumerability, just that this iterator would not be the default iterator for objects. If it's not in ES4, it should definitely be there because it's essential for those that want to customize enumerability. As was discussed before, the language cannot have such an iterator. Were this iterator to exist, an attacker could use it to discover hidden properties of objects, get access to private and other restricted namespaces, alter private state, and break through abstraction barriers. Waldemar ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
From: Neil Mix [mailto:[EMAIL PROTECTED] function __createProperty__(name:EnumerableId, value:*, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void On Thu, Mar 13, 2008 at 2:21 PM, Lars Hansen [EMAIL PROTECTED] wrote: This feels like convergence. I'll hook this into the RI and write it up in the next couple of days (barring further discussion, of course). I've been following this discussion and am quite happy with the overall direction! With these changes, ES3.1 should be a much friendlier base to subset into a Caja-like secure language. I'm hopeful that the resulting Caja-like language could safely be a much larger subset of ES3.1 than with current Caja vs ES3. I haven't yet thought these issues through well, but I'll offer some half baked suggestions for now. * As someone pointed out, using positional boolean flag parameters (..., false, true, false, ...) makes call-site readability too hard. This point was raised earlier but seems to have been dropped. IIRC, *all* the other parameterization suggestions had better call site readability. My favorite was simply a list of strings. OTOH, an advantage of the bit-mask approach is that sensible combinations of flags can be named and used simply. * I love Neil's suggestion of moving towards names saying what's allowed, rather than saying what's denied. I'd like to go further and suggest that __createProperty__ adopt the security best-practice of default-deny: When a property is explicitly created by this mechanism, only those operations that are explicitly allowed are permitted. All others attributes default to denying permission. To maintain compatibility of course, a property created the old fashioned way is implicitly fully permissive. * As Brendan reminds us, an erroneous __createProperty__ request should throw rather than failing silently or merely returning false. And a property access that fails because __createProperty__ did not allow it should also fail with a throw rather than silently. If we want to be strictly legacy compatible, then these throws should only happen for properties created with __createProperty__. Unfortunately, that means the semantics and implementations would need to distinguish, for example, legacy silently non-writable properties from new noisily non-writable properties. Can we instead specify that all these failures will be noisy? * Kris raises, we need to think about the interaction of these attributes with the notion of virtual properties defined using getters and setters. In particular, how does one create a non-removable virtual property? Should virtual properties have deleters in addition to getters and setters? * Might there be a sensible way to extend this mechanism to distinguish public from non-public properties? Based on the Caja design, might we adopt the rule that non-public property foo can only be addressed as this.foo or this['foo']. In other words, x.foo would only work is foo is public or unrestricted. The general approach we're following here for properties is: default to legacy-compatible overly-permissive behavior, but allow restriction to a fail-stop subset of this behavior. We should prefer to make expressible those restrictions that contribute to reasoning about integrity. (This is the right criteria whether on not one is trying to define a secure subset.) We should apply this general approach to objects as well as individual properties of objects. The most important, borrowed from ES4, is fixture vs dynamic. The Caja concept frozen then becomes exactly: fixture + all existing properties are non-writable and non-removable. We can even use this approach to clean up the main source of confusion in ES3 while preserving compatibility: What is the intended behavior of a function? It would be great to explicitly restrict a function to be callable only as a function, or only as a method, or only as a constructor, or only as a final constructor. An unrestricted function could continue to be callable in all these ways, as with ES3 functions. Moving these restrictions into the language would clear up a major source of vulnerability in the current Caja design: confused deputy dangers at the taming boundary between cajoled code and uncajoled code. If there's interest, I can expand on this issue. -- Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: Controlling DontEnum (was: ES4 draft: Object)
Speaking for myself, I should say from the outset that I am not in favor of taking this much further than it has been taken. The base language is ES3; we're trying to fix a small problem in that language in the cheapest possible way. I would rather backtrack to a solution that only fixes the DontEnum problem than to go forward into an elaborate design that attempts to fix various dodgy (or perceived as dodgy) features in the base language. Getters and setters should not be an issue. There is no way in ES4 to add a getter or setter to an object after the fact; getters and setters defined by an object initializer or in a class are fixtures and hence not deletable. (Some browsers have functions __defineGetter__ and __defineSetter__ that allow getters and setters to be added after the fact. Those are normally deletable. I suggest that these browsers expand their API to match that of __createProperty__.) --lars -Original Message- From: Mark S. Miller [mailto:[EMAIL PROTECTED] Sent: 13. mars 2008 17:22 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: Controlling DontEnum (was: ES4 draft: Object) From: Neil Mix [mailto:[EMAIL PROTECTED] function __createProperty__(name:EnumerableId, value:*, enumerable:boolean=true, removable:boolean=true, writable:boolean=true): void On Thu, Mar 13, 2008 at 2:21 PM, Lars Hansen [EMAIL PROTECTED] wrote: This feels like convergence. I'll hook this into the RI and write it up in the next couple of days (barring further discussion, of course). I've been following this discussion and am quite happy with the overall direction! With these changes, ES3.1 should be a much friendlier base to subset into a Caja-like secure language. I'm hopeful that the resulting Caja-like language could safely be a much larger subset of ES3.1 than with current Caja vs ES3. I haven't yet thought these issues through well, but I'll offer some half baked suggestions for now. * As someone pointed out, using positional boolean flag parameters (..., false, true, false, ...) makes call-site readability too hard. This point was raised earlier but seems to have been dropped. IIRC, *all* the other parameterization suggestions had better call site readability. My favorite was simply a list of strings. OTOH, an advantage of the bit-mask approach is that sensible combinations of flags can be named and used simply. * I love Neil's suggestion of moving towards names saying what's allowed, rather than saying what's denied. I'd like to go further and suggest that __createProperty__ adopt the security best-practice of default-deny: When a property is explicitly created by this mechanism, only those operations that are explicitly allowed are permitted. All others attributes default to denying permission. To maintain compatibility of course, a property created the old fashioned way is implicitly fully permissive. * As Brendan reminds us, an erroneous __createProperty__ request should throw rather than failing silently or merely returning false. And a property access that fails because __createProperty__ did not allow it should also fail with a throw rather than silently. If we want to be strictly legacy compatible, then these throws should only happen for properties created with __createProperty__. Unfortunately, that means the semantics and implementations would need to distinguish, for example, legacy silently non-writable properties from new noisily non-writable properties. Can we instead specify that all these failures will be noisy? * Kris raises, we need to think about the interaction of these attributes with the notion of virtual properties defined using getters and setters. In particular, how does one create a non-removable virtual property? Should virtual properties have deleters in addition to getters and setters? * Might there be a sensible way to extend this mechanism to distinguish public from non-public properties? Based on the Caja design, might we adopt the rule that non-public property foo can only be addressed as this.foo or this['foo']. In other words, x.foo would only work is foo is public or unrestricted. The general approach we're following here for properties is: default to legacy-compatible overly-permissive behavior, but allow restriction to a fail-stop subset of this behavior. We should prefer to make expressible those restrictions that contribute to reasoning about integrity. (This is the right criteria whether on not one is trying to define a secure subset.) We should apply this general approach to objects as well as individual properties of objects. The most important, borrowed from ES4, is fixture vs dynamic. The Caja concept frozen then becomes exactly: fixture + all existing properties are non
Re: ES4 draft: Object
On Mar 10, 2008, at 7:01 PM, Lars Hansen wrote: We are the WG. Are you saying that substantive discussions of your proposals are not welcome? Not sure what the point of participating is if that's the case. Sorry, I didn't realize that I find it abhorrent qualified as substantive discussion. My fault. Won't happen again. The optional second argument to make propertyIsEnumerable a setter has some practical problems: 1) It violates the very strong norm that getter and setter functions are separate and have their own different arguments. It will make the feature harder to use and code using it harder to understand, to some extent. 2) It makes it impossible to feature test for the ability to disable enumerability, compared to a separate setter. Against the argument that it is too risky compatibility-wise to add a new method to the object prototype (apparently the only reason things were done), I propose that it is overblown. Mozilla has defined new methods and properties on all objects. We have copied some in Safari and seen no web compatibility issues, I assume Mozilla has not had any as well. Specifically, I am thinking of __defineSetter__, __defineGetter__, __lookupSetter__, __lookupGetter__, and __proto__. Has any study been done on how many sites currently make use of the property names of a likely setter for propertyIsEnumerable? I'm dealing with a serious insurrection of folks who believe that the ES4 working group has a bad attitude, based on Brendan's public comments and responses to issues like this one. They're quite visible. Debate is only good. I merely pointed out the obvious thing, namely that until there is an alternative proposal written up to deal with this issue, the current design stands unless the WG, as a group, decides to just get rid of it (leaving the problem it was designed to solve solution-less). Surely reviewing this spec is the appropriate time to revisit this issue. I'd like to propose the following three alternatives to the current proposal: 1) Remove the feature entirely from ES4 (as part of the judicious feature cuts process) until a more appropriate syntax is found 2) Replace two-argument form of propertyIsEnumerable with setPropertyIsEnumerable 3) Replace two-argument form of propertyIsEnumerable with __setPropertyIsEnumerable__ I think each of these options is so trivial as to not require a lengthy write-up. What is the process for the WG deciding whether to make one of these changes, or something else? I like the idea of making non-public-namespaced properties be not-enumerable and getting rid of DontEnum. We've talked loosely about it for a while. But it's remained loose talk, it has never made it to the stage where it is a coherent proposal. I don't like syntax-based alternatives since they cannot be made to degrade gracefully in ES3 UAs. Regards, Maciej ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Insurrection (was: ES4 draft: Object)
On Mar 10, 2008, at 9:54 PM, Mark Miller wrote: ES3 has several abstraction mechanisms: * lambda abstraction, which it gets approximately as right as Scheme! * objects as a generalization of records, which has some pros and cons * prototype-based sharing of common behavior, which is used almost exclusively by JavaScript programmers to express only class-like patterns. Altogether, ES3 has many virtues and many problems. One of its great virtues is its almost perfect support for lexical nesting. Virtually any thisless construct that could appear at top level can also appear within a nested lexical context with the same meaning. ES3 also avoids the CommonLisp trap of multiple namespaces, instead siding with Scheme's single namespace approach. Even ignoring ES4's type system, ES4 adds all the following abstraction mechanisms to those in ES3: * classes * packages * units * namespaces You forgot interfaces (and the type system also adds record types, (sort-of)-tuples, typed arrays and parametric types). That does seem like a lot. - Maciej ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Insurrection (was: ES4 draft: Object)
ES3 has several abstraction mechanisms: * lambda abstraction, which it gets approximately as right as Scheme! * objects as a generalization of records, which has some pros and cons * prototype-based sharing of common behavior, which is used almost exclusively by JavaScript programmers to express only class-like patterns. Altogether, ES3 has many virtues and many problems. One of its great virtues is its almost perfect support for lexical nesting. Virtually any thisless construct that could appear at top level can also appear within a nested lexical context with the same meaning. ES3 also avoids the CommonLisp trap of multiple namespaces, instead siding with Scheme's single namespace approach. Even ignoring ES4's type system, ES4 adds all the following abstraction mechanisms to those in ES3: * classes * packages * units * namespaces You forgot interfaces (and the type system also adds record types, (sort-of)-tuples, typed arrays and parametric types). That does seem like a lot. There are also like / wrap types. Geoff ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mar 10, 2008, at 11:14 PM, Maciej Stachowiak wrote: The optional second argument to make propertyIsEnumerable a setter has some practical problems: 1) It violates the very strong norm that getter and setter functions are separate and have their own different arguments. It will make the feature harder to use and code using it harder to understand, to some extent. 2) It makes it impossible to feature test for the ability to disable enumerability, compared to a separate setter. Against the argument that it is too risky compatibility-wise to add a new method to the object prototype (apparently the only reason things were done), I propose that it is overblown. Mozilla has defined new methods and properties on all objects. We have copied some in Safari and seen no web compatibility issues, I assume Mozilla has not had any as well. Specifically, I am thinking of __defineSetter__, __defineGetter__, __lookupSetter__, __lookupGetter__, and __proto__. Has any study been done on how many sites currently make use of the property names of a likely setter for propertyIsEnumerable? I forgot to mention, making two-argument propertyIsEnumerable have setter semantics can be a tiny compatibility risk too, if any code accidentally calls it with two args and does not expect it to act as a setter in this case. Do we have any way to quantify the relative compatibility risk of the current design vs. a separate setter? Regards, Maciej ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mon, Mar 10, 2008 at 11:14 PM, Maciej Stachowiak [EMAIL PROTECTED] wrote: [...] I'd like to propose the following three alternatives to the current proposal: 1) Remove the feature entirely from ES4 (as part of the judicious feature cuts process) until a more appropriate syntax is found 2) Replace two-argument form of propertyIsEnumerable with setPropertyIsEnumerable 3) Replace two-argument form of propertyIsEnumerable with __setPropertyIsEnumerable__ So long as setPropertyIsEnumerable is a method of Object.prototype, it raises the otherwise pointless question of the meaning of overriding it. At the last ES3.1 face-to-face, we agreed instead on the following static method on Object, as recorded at http://wiki.ecmascript.org/doku.php?id=es3.1:targeted_additions_to_array_string_object_date: - Object.dontEnum(object, memberName) The own property memberName of object is marked to be excluded for the for in enumeration. If a new object is made that delegates to object, the new object may create and change its own memberName property, and that property will be enumerable. - That page also lists static methods on Object to set the attributes DontDelete and ReadOnly. The proposed static Object.fix(obj) is inspired by proposed ES4's notion of a fixture -- a non-dynamic object. Such static methods allow most of the restrictions associated with ES4's classes to be expressed without new syntax or major new concepts. -- Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mar 10, 2008, at 11:35 PM, Mark S. Miller wrote: On Mon, Mar 10, 2008 at 11:14 PM, Maciej Stachowiak [EMAIL PROTECTED] wrote: [...] I'd like to propose the following three alternatives to the current proposal: 1) Remove the feature entirely from ES4 (as part of the judicious feature cuts process) until a more appropriate syntax is found 2) Replace two-argument form of propertyIsEnumerable with setPropertyIsEnumerable 3) Replace two-argument form of propertyIsEnumerable with __setPropertyIsEnumerable__ So long as setPropertyIsEnumerable is a method of Object.prototype, it raises the otherwise pointless question of the meaning of overriding it. I don't see how it raises any special questions - it's not called internally by the implementation or anything. At the last ES3.1 face-to-face, we agreed instead on the following static method on Object, as recorded at http://wiki.ecmascript.org/doku.php?id=es3.1:targeted_additions_to_array_string_object_date : That proposal seems to depart markedly from the past plan that ES 3.1 is to be a subset of ES4. Has that plan been abandoned? ES3.1 organizers, what's up? (If you'd like to propose this design for ES4 as well then the basic approach seems sound, in that it avoids whatever risk there is to polluting the namespace of all objects without being conceptually confusing. Also the names lean too much towards terse instead of descriptive for such obscure operations. For instance Object.readOnly(o, p) would read much better as something like Object.makePropertyReadOnly(o, p).) Regards, Maciej ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On 11/03/2008, Maciej Stachowiak [EMAIL PROTECTED] wrote: This is not unreasonable, but if adding to Object.prototype is truly terrifying then I think the approach Mark Miller linked to, of static methods on the Object constructor, is cleaner: /snip/ It might even be better to make this transition one-way, since it shouldn't be allowed to make built-in properties that are DontEnum enumerable: Could as well make it a global function then. Just give it an obscure __preventEnumeration__(obj, propName) signature or something. I would very much like to see a declarative keyword for use with global, class and namespace variable and function declarations and in object literals. There's really not much reason to require a function call for a declarative feature if there's a cheap and much nicer way to do it in ES4, as long as you have a solution for ES3. (Kinda like how there's a specific slice syntax in ES4, but the slice functionality itself is ES3 compatible.) -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Yuh-Ruey Chen [EMAIL PROTECTED] wrote: Which gets me back to the cognitive load issue. Even with a name like 'hidden', they may think they may have to do some funky syntax like |obj.hidden::other_ns::prop| do hide a prop in another namespace. This was confusing me... How would you define a property to have a qualified name and be in the dontenum namespace at the same time? Or are namespaced properties non-enumerable anyway? (That would feel wrong to me..) namespace dontenum_ns = dontenum other_ns; obl.dontenum_ns::prop = 1; ? The problem here would be the property would always be accessible to all scopes, since only one of the namespaces needs to be open. ES4 doesn't currently have a way to express AND/OR namespace combinations. Peter ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Insurrection (was: ES4 draft: Object)
Hi Mark, I agree with a number of your objections. I hope you don't mind if I try to distinguish between some of the points I agree with and disagree with. The current fad in language design is expressive static type systems. As a result, several recent type systems have grown eat their language. Java 1.5 is a particularly nasty example. Simple bits of Java code become so overwhelmed by complex type declarations as to obscure the logic of the code itself. Proposed ES4 suffers from the same disease, though it has not (yet) come down with as bad a case as Java. I'd love for us to get past the points about popularity and fads. I know that static types are all the rage and that dynamic languages have consequently suffered in the court of popular opinion. I'm a member of the Scheme community so I feel it acutely. But I'm skeptical of your comparison to Java 5. Java is a statically typed language that gained even more types. The ES4 proposal is a dynamic language with optional type annotations. These are there to help people when they feel that types would serve to document their code and type checking would help improve the robustness of their code and/or make the kinds of ad-hoc checking (hand-written assertions) cleaner. When people don't feel they add value, they don't have to use them. In Java 5, you're locked in to complex type annotations and can't get out. An important design goal in the ES4 type system has been to make the relationship between typed and untyped code relaxed enough that this doesn't happen. Even ignoring ES4's type system, ES4 adds all the following abstraction mechanisms to those in ES3: * classes * packages * units * namespaces I'm sympathetic-- I've always been uncomfortable with packages and namespaces. (My reaction to units was more hopeful, since the global object is so problematic in ES3, but I'm not yet up to speed on the proposal.) If instead classes, for example, were defined purely by syntactic expansion to the constructs in ES3.1, then classes would inherit the lexical nestability of the constructs they expand into. Even Java's classes are lexically nestable! Nestability is a good design goal, and I'm glad you brought it up. Syntactic expansion has many benefits, too, of course. I just want to point out the main pitfall in making classes syntactic sugar. One of the real problems with ES3 is the inability to make guarantees about any bindings except for lexical ones. With vanilla ES3 objects, there's no way to share information between (conceptual) modules of code and preserve the integrity of the container, unless you either a) hide the data in a closure or b) copy the data into a dummy container. Classes, in addition to being a well-understood mechanism and the de facto style of the JS community, should help the programmer protect the integrity of their bindings. For example, a class declaration in ES4 creates fixtures for its properties-- meaning that the programmer can rely on them not being deleted. The current ad hoc approaches in use in ES3 can't guarantee that, and manually using closures is too heavyweight. That said, you've hinted at alternative approaches, perhaps with constructs desugaring to closures of some sort: The namespace mechanism seems motivated by a failure to appreciate the power available by modest extensions of simple lambda abstraction. I'd certainly like to hear what you're thinking here. Why should we prefer foo::bar::baz? What is gained by having two mechanisms? Fair criticisms (and I personally feel the namespace mechanism is one of the most deserving of criticism). Primarily, the purpose it's serving is a way to protect object properties with a key that you can then control via e.g. lexical hiding. The Foo.Bar.baz pattern in ES3 doesn't provide a way to hide such bindings. When I first read the overview, I was puzzled by the lack of uniformity between the types [int] and [int, String]. IIUC, the first represents the type of all arrays *all* of whose elements are ints. That's not my understanding. IIRC, for a type [T1,...,Tn,Tn+1] there are required to be zero or more array elements of Tn+1. So [int] is the type of arrays with zero or more ints, and [int, String] is the type of arrays with an int at index 0 followed by zero or more Strings. I'll grant that this is unconventional. But it's an attempt to make the type structure match actual usage in JS: people use arrays both as arrays and as tuples. So we have a type that accomodates the idiomatic usage of the language. Dave ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
1) Remove the feature entirely from ES4 (as part of the judicious feature cuts process) until a more appropriate syntax is found Setting dontEnum is immensely valuable as a framework developer. I realize that is not a very technical argument, but controlling dontEnum is of more value than many of the other features in ES4, and would certainly hope it is not omitted. So long as setPropertyIsEnumerable is a method of Object.prototype, it raises the otherwise pointless question of the meaning of overriding it. At the last ES3.1 face-to-face, we agreed instead on the following static method on Object, as recorded at http://wiki.ecmascript.org/doku.php?id=es3.1:targeted_additions_to_array_string_object_date: - Object.dontEnum(object, memberName) I realize I wasn't there (at the ES3.1 F2F, only called in), but why was this discussed for ES3.1? I thought the page you are referencing was simply items that hadn't been cleaned up yet, since it clearly does not subset ES4 (as I noted in my comments on that page). If we desire that this be a part of ES3.1, it should be brought up as a proposal for ES4, so that ES3.1 can safe subset it, rather than creating new divergent features for ES3.1. Frankly, I like the idea of using Object.dontEnum(object, memberName), that sounds great to me, but it should be an ES4 proposal first and should not be considered for inclusion in ES3.1 unless and until accepted by ES4. BTW, Another possible syntax could be: Object.setAttribute(object, memberName,attributeFlag) which could be used to set the dontEnum, readOnly, and dontDelete flags and probably more closely follows the internal structure of implementations as well. Thanks, Kris ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Peter Hall wrote: Yuh-Ruey Chen [EMAIL PROTECTED] wrote: Which gets me back to the cognitive load issue. Even with a name like 'hidden', they may think they may have to do some funky syntax like |obj.hidden::other_ns::prop| do hide a prop in another namespace. This was confusing me... How would you define a property to have a qualified name and be in the dontenum namespace at the same time? Or are namespaced properties non-enumerable anyway? (That would feel wrong to me..) The latter. It is weird, I agree. But the enumerator can easily be customized, so I want the default enumerator be as non-magical as possible - and therefore, as simple as possible. In fact, I'm a bit bothered that propertyIsEnumerable is a method of Object yet can be rendered useless when changing the enumerator - along this line of reasoning, one would think that such a specific method shouldn't be a method of Object at all, but rather the enumerator itself. ES4 doesn't currently have a way to express AND/OR namespace combinations. Yeah, I vaguely remember some discussion concerning multiple namespaces per property a long time ago (maybe a year ago). It was rejected probably due to complexity. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
The latter. It is weird, I agree. But the enumerator can easily be customized, so I want the default enumerator be as non-magical as possible - and therefore, as simple as possible. In fact, I'm a bit bothered that propertyIsEnumerable is a method of Object yet can be rendered useless when changing the enumerator - along this line of reasoning, one would think that such a specific method shouldn't be a method of Object at all, but rather the enumerator itself. So how would you go about enumerating the properties of an arbitrary dynamic object, whose properties could be in namespaces? Yeah, I vaguely remember some discussion concerning multiple namespaces per property a long time ago (maybe a year ago). It was rejected probably due to complexity. Not being able to combine them effectively makes many of the initial proposal's use-cases useless, because two use-cases may arise simultaneously when integrating two codebases, and be irreparably conflicting. Peter ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mar 11, 2008, at 1:14 AM, Maciej Stachowiak wrote: The optional second argument to make propertyIsEnumerable a setter has some practical problems: 1) It violates the very strong norm that getter and setter functions are separate and have their own different arguments. It will make the feature harder to use and code using it harder to understand, to some extent. 2) It makes it impossible to feature test for the ability to disable enumerability, compared to a separate setter. I agree with these points. Against the argument that it is too risky compatibility-wise to add a new method to the object prototype (apparently the only reason things were done), No, that was not the only reason. The other reason (it may be a bad reason, but I pointed it out in an earlier message to make it apparent): so calls passing two arguments would not cause ES3 implementations to fail as would undetected calls to a new method. But I agree that the numbered points you make are sufficient to reconsider the two-argument proposal that was accepted a while go. Just for the es4-discuss list's information, I want to provide some historical context. the working group at that time had many large and small issues to grapple with, so we did not dedicate too much time to the Prototype Ajax library problem (wanting to set DontEnum on user- defined properties). We were not so much in favor of the _de minimus_ second argument idea that was quickly settled on, as we were opposed to adding another method with a plain name to Object.prototype. And even that wasn't a strong objection, in light of namespaces (more below on that). This was at the time very much small potatoes, which I for one am happy to revisit (I've already sketched a namespace-based alternative). It should not be used to impeach the entirely of the group's work. I propose that it is overblown. Mozilla has defined new methods and properties on all objects. In 1998 or 1999, we added meta methods and properties, distinguished (after Python) by leading and trailing double underscores. We haven't tried adding a plainly named property to Object.prototype in quite a while. We have copied some in Safari and seen no web compatibility issues, I assume Mozilla has not had any as well. Specifically, I am thinking of __defineSetter__, __defineGetter__, __lookupSetter__, __lookupGetter__, and __proto__. These are all metaprogramming hooks, but so arguably is __setPropertyIsEnumerable__ -- so I agree with your reasoning here. Has any study been done on how many sites currently make use of the property names of a likely setter for propertyIsEnumerable? We have not crawled the web looking for plain-named methods, but we have spidered for other patterns we proposed to change incompatibly, and the results are not decisive. For example, looking for attempts to rebind standard constructors found only a dead MSN .js file rebinding Error, but when we tried in Firefox 3 beta 2 to lock down the global bindings for Date, etc., we found many sites and web apps breaking. This is a different case, of course, but my point stands: searching the web is informative, but not decisive. Debate is only good. I merely pointed out the obvious thing, namely that until there is an alternative proposal written up to deal with this issue, the current design stands unless the WG, as a group, decides to just get rid of it (leaving the problem it was designed to solve solution-less). Surely reviewing this spec is the appropriate time to revisit this issue. Yes, and this list is the right place. It's pretty clear Lars agrees, and nothing he wrote cited above contradicts it. So let's discuss more. I'd like to propose the following three alternatives to the current proposal: 1) Remove the feature entirely from ES4 (as part of the judicious feature cuts process) until a more appropriate syntax is found 2) Replace two-argument form of propertyIsEnumerable with setPropertyIsEnumerable 3) Replace two-argument form of propertyIsEnumerable with __setPropertyIsEnumerable__ I think each of these options is so trivial as to not require a lengthy write-up. What is the process for the WG deciding whether to make one of these changes, or something else? Arguing here in es4-discuss might be enough, if the argument makes progress and the participants reach a consensus. I like the idea of making non-public-namespaced properties be not-enumerable and getting rid of DontEnum. We've talked loosely about it for a while. But it's remained loose talk, it has never made it to the stage where it is a coherent proposal. I don't like syntax-based alternatives since they cannot be made to degrade gracefully in ES3 UAs. I think that's a good point too, since as noted above it was one of the two reasons for the lame-duck two-argument proposal we've accepted. /be ___ Es4-discuss
Controlling DontEnum (was: ES4 draft: Object)
Here is a modest proposal based on Mark's and Maciej's messages: Goal: A detectable method requiring no new syntax to set the DontEnum attribute on an existing property. Goal: Avoid breaking any existing ES3 code that might depend on a plainly named method not being predefined. Anti-goal: The ability to turn off DontEnum where it has been set on predefined properties. Proposal: Add Object.prototype.__makePropertyNonEnumerable__(name), defined as if by: Object.prototype.__makePropertyNonEnumerable__ = function (name) { if (this has a direct property identified by name) { set the DontEnum attribute for this[name]; return true; } return false; } Note that if this has a direct property identified by name, but this [name] already has the DontEnum attribute, then the function returns true. The specification with prose of setting DontEnum would occur redundantly in this case, but it is not observable in ES3 or ES4 as proposed, so for simplicity I left out a test of DontEnum to avoid a redundant set. The use of a __-bracketed name satisfies the second goal, but it would be a problem for Caja or similar. This is an issue where I would appreciate Mark's feedback. Comments welcome. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
The use of a __-bracketed name satisfies the second goal, but it would be a problem for Caja or similar. This is an issue where I would appreciate Mark's feedback. I can't speak for Mark, but it seems like it might actually be beneficial that unsecured code (regular ES4) would have the ability to set DontEnum and secured code (Secure ES, Cajoled Caja, ADsafe, or whatever) wouldn't have that capability. +1 Kris ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
If there is no method to make a property enumerable again (which I now agree is better not to exist) it feels somehow bad to be able to make a property non-enumerable after its declaration. Consider: let a = {b:2, c:3}; for(let s in a){ print(s); // b, c } a.__makePropertyNonEnumerable__(b); for(let s in a){ print(s); // c } It seems wrong that the code should run once one way, and then another way, but there be no way back. It's not so much that I think there should be a way back, but I'd rather that than this, which I consider a weird situation. Also the double underscores are really ugly syntax... Perhaps you can't achieve this without new syntax, but the declarative approach seems cleanest and not prone to this sort of anomaly. If new syntax could be considered, an |enumerable| attribute, complemented by a |!enumerable| attribute seems very clean. type T = {enumerable a:int, b:int}; let t:T = {a:1, b:2}:T; // a is enumerable, b is not let s = {a:1, !enumerable b:1}; // a is enumerable, b is not class C { enumerable var p; } Peter On Tue, Mar 11, 2008 at 7:45 PM, Brendan Eich [EMAIL PROTECTED] wrote: Here is a modest proposal based on Mark's and Maciej's messages: Goal: A detectable method requiring no new syntax to set the DontEnum attribute on an existing property. Goal: Avoid breaking any existing ES3 code that might depend on a plainly named method not being predefined. Anti-goal: The ability to turn off DontEnum where it has been set on predefined properties. Proposal: Add Object.prototype.__makePropertyNonEnumerable__(name), defined as if by: Object.prototype.__makePropertyNonEnumerable__ = function (name) { if (this has a direct property identified by name) { set the DontEnum attribute for this[name]; return true; } return false; } Note that if this has a direct property identified by name, but this [name] already has the DontEnum attribute, then the function returns true. The specification with prose of setting DontEnum would occur redundantly in this case, but it is not observable in ES3 or ES4 as proposed, so for simplicity I left out a test of DontEnum to avoid a redundant set. The use of a __-bracketed name satisfies the second goal, but it would be a problem for Caja or similar. This is an issue where I would appreciate Mark's feedback. Comments welcome. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On Tue, Mar 11, 2008 at 2:32 PM, Peter Hall [EMAIL PROTECTED] wrote: Perhaps you can't achieve this without new syntax, but the declarative approach seems cleanest and not prone to this sort of anomaly. If new syntax could be considered, an |enumerable| attribute, complemented by a |!enumerable| attribute seems very clean. type T = {enumerable a:int, b:int}; let t:T = {a:1, b:2}:T; // a is enumerable, b is not let s = {a:1, !enumerable b:1}; // a is enumerable, b is not class C { enumerable var p; } Hi Peter, I like the idea of a more declarative approach as well, if one can be found. However, this proposal has two problems from our perspective: * It introduces new syntax, as you mention. * It depends on the proposed ES4 type system which is unacceptable to the ES3.1 effort. ES3.1 needs a way to express these integrity constraints in the absence of ES4 types. -- Text by me above is hereby placed in the public domain Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
[+google-caja-discuss] On Tue, Mar 11, 2008 at 12:53 PM, Kris Zyp [EMAIL PROTECTED] wrote: The use of a __-bracketed name satisfies the second goal, but it would be a problem for Caja or similar. This is an issue where I would appreciate Mark's feedback. I can't speak for Mark, but it seems like it might actually be beneficial that unsecured code (regular ES4) would have the ability to set DontEnum and secured code (Secure ES, Cajoled Caja, ADsafe, or whatever) wouldn't have that capability. +1 Kris I think Kris is right, but I'm not yet sure. I've forwarded this thread to [EMAIL PROTECTED] for discussion of what would be the best ways to support Caja's needs. Nono of these issues are specific to DontEnum. They affect all other integrity restriction attributes, such as ReadOnly, DontDelete, and fixture (i.e., non-dynamic). -- Text by me above is hereby placed in the public domain Cheers, --MarkM ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
It seems wrong that the code should run once one way, and then another way, but there be no way back. It's not so much that I think there should be a way back, but I'd rather that than this, which I consider a weird situation. Declarative is nice, but as mentioned before, it ignores one of the primary use cases: addition of non-enumerable properties to built-ins (by libraries, primarily). Also the double underscores are really ugly syntax... That's the idea, no one is currently using such an ugly method ;). Kris ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On Mar 11, 2008, at 5:16 PM, Kris Zyp wrote: Declarative is nice, but as mentioned before, it ignores one of the primary use cases: addition of non-enumerable properties to built-ins (by libraries, primarily). I've read mention of the weirdness of the timing window between the property definition and it's marking as non-enumerable. That combined with the above observation makes me wonder if this should really be obj.__setNonEnumerableProperty__(name, value); ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
On Mar 11, 2008, at 3:21 PM, Neil Mix wrote: On Mar 11, 2008, at 5:16 PM, Kris Zyp wrote: Declarative is nice, but as mentioned before, it ignores one of the primary use cases: addition of non-enumerable properties to built-ins (by libraries, primarily). I've read mention of the weirdness of the timing window between the property definition and it's marking as non-enumerable. That combined with the above observation makes me wonder if this should really be obj.__setNonEnumerableProperty__(name, value); +1 /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: Controlling DontEnum (was: ES4 draft: Object)
I've read mention of the weirdness of the timing window between the property definition and it's marking as non-enumerable. That combined with the above observation makes me wonder if this should really be obj.__setNonEnumerableProperty__(name, value); +1 I like it too. Any chance that by setting the attribute at the same time of setting the property value, we could resurrect the possibility of setting other attributes as well (with a single method): Object.prototype.__setPropertyWithAttributes__(name, value, dontEnum: boolean, readOnly: boolean, dontDelete: boolean); And various proposed syntax like: obj = {dontenum a: 1, const b: 2, var c: 3}; could be written: obj = {}; obj.__setPropertyWithAttributes__(a,1,true); // property a is not enumerable obj.__setPropertyWithAttributes__(b,2,false,true); // property b is readonly obj.__setPropertyWithAttributes__(c,3,false,false,true); // propery c is permanent I wonder if readonly and dontdelete are other attributes where there might be benefits derived from trusted code (regular ES3/4) being able to control, and untrusted code (ses, caja) not being able to control. I can't think of what those benefits might be, maybe another question for Mark or Doug to think on. Kris ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
Draft 2 of the spec for the Object class. Changelog near the beginning. --lars Title: The class "Object" The class Object NAME: "The class 'Object'" FILE: spec/library/Object.html CATEGORY: Pre-defined classes (E262-3 Chapter 15) SOURCES:REFERENCES [1], [2] SPEC AUTHOR:Lars DRAFT STATUS: DRAFT 2 - 2008-03-10 REVIEWED AGAINST ES3: YES REVIEWED AGAINST ERRATA:YES REVIEWED AGAINST BASE DOC: YES REVIEWED AGAINST PROPOSALS: YES REVIEWED AGAINST CODE: YES IMPLEMENTATION STATUS: ES4RI TEST CASE STATUS: ? CHANGES SINCE DRAFT 1 (2008-03-05) * More elaborate status block above * Prototype methods do not delegate to the corresponding intrinsic methods, but to shared private methods that are also called by the intrinsic method. In this fashion, prototype method behavior is invariant of subclassing. * Introduction of a specification-only protocol helper::getClassName for overriding class names for ES3 compatibility. NOTES * The use of 'Private' instead of 'private' below is a workaround for a bug in the reference implementation (#368). * The function 'helper::toEnumerableId' converts an arbitrary value to a member of 'EnumerableId': int, uint, string, or Name. It is specified elsewhere but in general you can think of it as converting any number to int or uint, leaving strings and Names alone, and converting everything else to string. REFERENCES [1] [1] http:wiki.ecmascript.org/doku.php?id=proposals:enumerability [2] builtins/Name.es in the ES4 RI The class Object is a dynamic non-final class that does not subclass any other objects: it is the root of the class hierarchy. All values in ECMAScript except undefined and null are instances of the class Object or one of its subclasses. NOTE Host objects may not be instances of Object or its subclasses, but must to some extent behave as if they are (see Host objects). Synopsis The class Object provides this interface: public dynamic class Object { public function Object(value=undefined) static meta function invoke(value=undefined) static public const length = 1 intrinsic function toString() : string intrinsic function toLocaleString() : string intrinsic function valueOf() : Object intrinsic function hasOwnProperty(name: EnumerableId): boolean intrinsic function isPrototypeOf(value): boolean intrinsic function propertyIsEnumerable(name: EnumerableId, flag: (boolean|undefined) = undefined): boolean } The Object prototype object provides these direct properties: toString: function () , toLocaleString: function () , valueOf: function () , hasOwnProperty: function (name) , isPrototypeOf:function (value) , propertyIsEnumerable: function (name, flag=undefined) , The Object prototype object is itself an instance of the class Object, with the exception that the value of its [[Prototype]] property is null. Methods on the Object class object newObject(value=) Description When the Object constructor is called with an argument value (defaulting to undefined) as part of a new _expression_, it transforms the value to an object in a way that depends on the type of value. Returns The Object constructor returns an object (an instance of Object or one of its subclasses, or a host object). NOTE The Object constructor is the only constructor function defined on a class in the language whose result may be a value of a different class than the one in which the constructor is defined. Implementation The Object constructor can't be expressed as a regular ECMAScript constructor. Instead it is presented below as a helper function makeObject that the ECMAScript implementation will invoke when it evaluates new Object. The helper function makeObject only is invoked on native ECMAScript values. If new Object is evaluated on a host object, then actions are taken and a result is returned in an implementation dependent manner that may depend on the host object. helper function makeObject(value=undefined) { switch type (value) { case (s: string) { return new String(s); } case (b: boolean) { return new Boolean(b); } case (n: (int|uint|double|decimal)) { return new Number(n); } case (x: (null|undefined)) { return magic::createObject(); } case (o: Object) { return o; } } } Object(value=) Description When the Object class object is called as a function with zero or one arguments it performs a type conversion. Returns It returns the converted value. Implementation static meta function invoke(value=undefined) new Object(value); Methods on Object instances The intrinsic methods on Object instances delegate to private methods that are also
Re: ES4 draft: Object
On 10/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: Draft 2 of the spec for the Object class. Changelog near the beginning. The draft HTML seems a little broken. There's amp;#x0085 in it early on, later these appear raw in the source (which displays as an empty square in Opera and IE8). And near the end of the document you have /p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/div Slightly broken conversion tool? -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: On Mar 9, 2008, at 3:01 PM, Yuh-Ruey Chen wrote: Brendan Eich wrote: ES3 code can't detect namespaces, so arguably shouldn't care if we were to implement DontEnum using an open namespace. But this could be a problem for mixed ES3 and ES4 scenarios where the ES4 code does introspect via Name objects and is surprised to find ES3 objects with qualified property names. I'm talking about how the enumerability (or lack thereof) of Object.prototype.* are determined. Or are prototype methods also not enumerable by default like fixtures? My reply was not meant to be an answer, but a question: should we drop this dontenum-namespace idea because it will break ES3+ES4 mixtures where the ES4 code reflects on a property's namespace qualifier by using a Name object? Does this included ES3-style prototype methods? And would it be possible to init a fixture to be enumerable? In the sketch I mailed, you didn't see any mention of fixtures -- IIRC you asked about them in reply. Just to explain what my proposal was aiming to do: It seems to me that if we have to add a magic bit back into the skinny is-it-enumerable decision tree, we may as well keep DontEnum. And the RI does print it, so I'm not sure what you're talking about. The RI is (a) not normative (nothing apart from ES3+fixes is yet), (b) based on a DontEnum attribute model, not on my proposal. Not sure why you thought I was talking about it. I was making a new proposal. Ok, that cleared things up a bit. I didn't realize you were making a proposal and asking questions based off it :) I thought you were mentioning how the RI was implemented today at the moment. Can you elaborate on cases where ES4 code does introspect via Name objects and is surprised to find ES3 objects with qualified property names.? I can't think of any. BTW, what exactly is a fixture? That's a good question, and it seems the answer is not in the wiki. Trying the trac: http://bugs.ecmascript.org/ticket/233 which references the overview document. In ES3 terms, a fixture is a property with the DontDelete attribute set. But there's more to it than that, for reasons expanded on in #233 to do with namespace lookup and early binding. And there is another case that Lars pointed out recently to do with dynamic classes, but I'll avoid trying to summarize it except to say that a fixture is a fixed property that can't be deleted or shadowed. Thanks, that's a good summary, though some of the commentary in the ticket was confusing (like lth's example - was x.toString decided to be ambiguous?). Is that the right design? dynamic class C { public var fixture; function C() { this.expando = 42; } } for (var i in new C) intrinsic::print(i); wouldn't you expect to see expando printed? Is it printed because the default namespace for expando is the public-default one? I believe it is not, in the current proposal and the RI. Rather, each class or package gets a nonce-named public namespace, different from every other such per-class or per-package public. IIRC package trumps class -- classes within a package share the package's nonce-named public namespace (Jeff, Lars, please correct me if I'm wrong). I meant non-expando vars and methods defined within the class, whatever the terminology is used (I see 'fixture' thrown around everywhere), are not enumerable. So yes, expando should be printed. From your numbered steps above, step 3 must have been reached -- so expando is in the public-public (null qualifier in Name object reflection) namespace. Not in the class-C-public namespace. My question is whether that is the right design choice. Are they any particular disadvantages that you can think of? Maybe another ES4 designer can chime in here. BTW, a bit off topic: if a class is defined in a namespace, are the properties of that class also defined in that namespace (instead of just public/class-public)? Namespaces aren't clearly specified in the wiki or the overview, the tickets are unorganized, and the RI tends to barf when it comes to them. Ugh, I feel Apple's pain when they complain that they don't know where to start... Are you saying that each property is defined in a class-specific public namespace, and therefore does not get enumerated? I would say that expando properties should be defined in the global public namespace, so that they would be enumerated. Ok, I like that. I'm not arguing a side, just showing the choice. There may be other cases, though, where a class-public property name might want to be enumerable. In such a case the step 2 you wrote would need to elaborate its public test. But again, my proposal was about enumerability, independent of fixture-ness. /be Yeah, I asked whether it was possible to make a class-public property enumerable. And if so, I really
Re: ES4 draft: Object
intrinsic function propertyIsEnumerable(name: EnumerableId, flag: (boolean|undefined) = undefined): boolean I too find the second parameter here abhorrent. Please find another way to solve it (Brendan's namespace idea maybe) or remove this feature altogether. How does property lookup deal with properties indexed by numbers that are not int or uint? toEnumerableId converts them to strings, but the Vector proposal indicated that vectors don't. Waldemar ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of liorean Sent: 10. mars 2008 17:52 To: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object On 10/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: Draft 2 of the spec for the Object class. Changelog near the beginning. ~~intrinsic::toString ( )~~ The intrinsic toString method returns the concatenation of [, object, the class name of the object, and ]. There should probably be a whitepace between object and the class name, as is the case in the implementation. There should. Corrected. ~~intrinsic::valueOf ( )~~ If the object is the result of calling the Object constructor with a host object (Host objects), it is implementation-defined whether valueOf returns its this value or another value such as the host object originally passed to the constructor. (Host objects) looks a bit weird like that. Should probably be either (see Host objects) analogously to how you later use (see HasProperty-defn) or reference style, [Host objects] Corrected. ~~intrinsic::isPrototypeOf ( value )~~ The function magic::getPrototype extracts the [[Prototype]] property from the object. See magic:getPrototype. And here a reference to documentation elsewhere. Probably should try to be consistent about how those look. I assume these are going to be links in the finished spec? The primary format of the final spec is word and/or pdf, so I don't know about links there. I hope that we can release an HTML version too, and obviously it would be good if there could be good hyperlinking there. I would like to promise all of that but I am not going to do it. However, there will at least be proper references to the sections that define the magic functions. In general the specification of the magic functions is somewhat unstructured at present. I appreciate this reminder about that :-) --lars -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: Waldemar Horwat [mailto:[EMAIL PROTECTED] Sent: 10. mars 2008 18:50 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object intrinsic function propertyIsEnumerable(name: EnumerableId, flag: (boolean|undefined) = undefined): boolean I too find the second parameter here abhorrent. Please find another way to solve it (Brendan's namespace idea maybe) or remove this feature altogether. The feature was approved by the WG and solves a practical problem. If another way to solve this practical problem is proposed (in a more structured form than in the ongoing discussion) and finds favor with the WG, then fine -- of course we can replace it. Until then, this feature stays as it is until the WG can be convinced that it needs to be removed. Personally I think that it is ugly/abhorrent is a weak basis on which to remove the current feature. How does property lookup deal with properties indexed by numbers that are not int or uint? toEnumerableId converts them to strings, but the Vector proposal indicated that vectors don't. The intrinsic::hasOwnProperty and intrinsic::propertyIsEnumerable methods on Object require EnumerableId parameters, and no conversion happens automatically when they are called (there should be no automatic conversion to union types, even from a number to a number in the type). So programs trying to call the intrinsic methods on doubles (say) will receive errors. This is true independent of Vector. The prototype methods inherited from Object perform conversions explicitly, but can be overridden in Vector to prevent the conversion. Ergo the hasOwnProperty and propertyIsEnumerable methods on Vector should be able to handle arbitrary names, and should return false for all property names that are numbers not in the uint range -- if that's what we think is the desired behavior. That said, you raise a good point and I don't think the story is fully coherent yet. Certainly we don't have a working prototype of this. (And yet another point is that I expect that the int and uint types are not going to be in the final language and that some of the machinery in Object will have to be rethought as a consequence of that change.) --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
As far as I can see this is not a problem in the file I sent out, nor in the one I received from the reflector. What mailer are you using? Anyone else see this? --lars -Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of liorean Sent: 10. mars 2008 17:18 To: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object On 10/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: Draft 2 of the spec for the Object class. Changelog near the beginning. The draft HTML seems a little broken. There's amp;#x0085 in it early on, later these appear raw in the source (which displays as an empty square in Opera and IE8). And near the end of the document you have /p/p/p/p/p/p/p/p/p/p/p/p/p/p/p /p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p /p/p/p/p/p/p/p/p/p/p/p/p/p/p/p /p/p/p/p/p/p/p/p/p/p/p/p/p/p/p/p /p/p/p/p/p/p/p/p/div Slightly broken conversion tool? -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On 11/03/2008, Lars Hansen [EMAIL PROTECTED] wrote: As far as I can see this is not a problem in the file I sent out, nor in the one I received from the reflector. What mailer are you using? Gmail's web interface. And checking, it appears only using the View link, not the Download link. So it appears to be GMail's fault. -- David liorean Andersson ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Lars Hansen wrote: The feature was approved by the WG and solves a practical problem. If another way to solve this practical problem is proposed (in a more structured form than in the ongoing discussion) and finds favor with the WG, then fine -- of course we can replace it. Until then, this feature stays as it is until the WG can be convinced that it needs to be removed. Personally I think that it is ugly/abhorrent is a weak basis on which to remove the current feature. We are the WG. Are you saying that substantive discussions of your proposals are not welcome? Not sure what the point of participating is if that's the case. I'm dealing with a serious insurrection of folks who believe that the ES4 working group has a bad attitude, based on Brendan's public comments and responses to issues like this one. They're quite visible. Waldemar ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: Waldemar Horwat [mailto:[EMAIL PROTECTED] Sent: 10. mars 2008 19:40 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object Lars Hansen wrote: The feature was approved by the WG and solves a practical problem. If another way to solve this practical problem is proposed (in a more structured form than in the ongoing discussion) and finds favor with the WG, then fine -- of course we can replace it. Until then, this feature stays as it is until the WG can be convinced that it needs to be removed. Personally I think that it is ugly/abhorrent is a weak basis on which to remove the current feature. We are the WG. Are you saying that substantive discussions of your proposals are not welcome? Not sure what the point of participating is if that's the case. Sorry, I didn't realize that I find it abhorrent qualified as substantive discussion. My fault. Won't happen again. I'm dealing with a serious insurrection of folks who believe that the ES4 working group has a bad attitude, based on Brendan's public comments and responses to issues like this one. They're quite visible. Debate is only good. I merely pointed out the obvious thing, namely that until there is an alternative proposal written up to deal with this issue, the current design stands unless the WG, as a group, decides to just get rid of it (leaving the problem it was designed to solve solution-less). I like the idea of making non-public-namespaced properties be not-enumerable and getting rid of DontEnum. We've talked loosely about it for a while. But it's remained loose talk, it has never made it to the stage where it is a coherent proposal. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mon, Mar 10, 2008 at 11:11 PM, Jeff Dyer [EMAIL PROTECTED] wrote: it would be helpful to follow up with possible solutions or at least insight into what makes it abhorrent (your word). FWIW, I also did not grasp the force of the objection, and would like to understand better. No doubt the WG has attitude. There are strong personalities involved and we have had our share of knocks. Sometimes that shows. It can probably show less if everyone makes an effort. The WG has most of the implementors one could hope for, so this opportunity shouldn't be wasted. -- Robert Sayre I would have written a shorter letter, but I did not have the time. ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Insurrection (was: ES4 draft: Object)
On Mon, Mar 10, 2008 at 8:11 PM, Jeff Dyer [EMAIL PROTECTED] wrote: On 3/10/08 5:40 PM, Waldemar Horwat wrote: I'm dealing with a serious insurrection of folks who believe that the ES4 working group has a bad attitude, based on Brendan's public comments and responses to issues like this one. They're quite visible. No doubt the WG has attitude. There are strong personalities involved and we have had our share of knocks. Sometimes that shows. You of all people should understand why. But please do share more about the insurrection you are dealing with. Maybe then we can be more sensitive. I hope Waldemar is not counting me as a member of that insurrection. My problem with the ES4 proposal has nothing to do with the attitude and personality of the ES4 WG members. Quite the opposite. I have come to like and respect those of you I have come to know. Since Brendan is mentioned explicitly above, I'll mention the high regard I've come to have for Brendan in particular. I have also enjoyed every encounter I have had with the group as a whole. A vague disclaimer is nobody's friend. --Willow Rosenberg, Buffy episode: The Initiative True friends stab you in the front. --Oscar Wilde I do not wish to offend anyone. I know I am speaking harshly about work that many here have invested in heavily. But in the interests of clarity, I will speak plainly below. I hope the discussion will continue from here with its customary civility. I have serious problems with the proposed ES4 *design* -- to the point that I have a hard time taking it seriously. I hope and expect that it will be crushed by its own weight. I fear that it might become widely adopted, and we will instead be crushed by it. In any case, I have decided that my energies as a new EcmaScript committee member are better spent on the ES3.1 WG, as the other members of that WG seem similarly inclined to look for the *smallest* reasonable language that meets our goals http://wiki.ecmascript.org/doku.php?id=es3.1:es3.1_goals. The current fad in language design is expressive static type systems. As a result, several recent type systems have grown eat their language. Java 1.5 is a particularly nasty example. Simple bits of Java code become so overwhelmed by complex type declarations as to obscure the logic of the code itself. Proposed ES4 suffers from the same disease, though it has not (yet) come down with as bad a case as Java. I applaud Jeff's and Lars' recent document of proposed deferrals from proposed ES4. After reading this document carefully, I was then able to reread the proposed ES4 overview document and imagine the smaller language they are suggesting. This language I still believe to be too large, but at least it would now be small enough to be worth criticizing. ES3 has several abstraction mechanisms: * lambda abstraction, which it gets approximately as right as Scheme! * objects as a generalization of records, which has some pros and cons * prototype-based sharing of common behavior, which is used almost exclusively by JavaScript programmers to express only class-like patterns. Altogether, ES3 has many virtues and many problems. One of its great virtues is its almost perfect support for lexical nesting. Virtually any thisless construct that could appear at top level can also appear within a nested lexical context with the same meaning. ES3 also avoids the CommonLisp trap of multiple namespaces, instead siding with Scheme's single namespace approach. Even ignoring ES4's type system, ES4 adds all the following abstraction mechanisms to those in ES3: * classes * packages * units * namespaces I have not heard anyone explain any of these as syntactic sugar that could be expanded away into remaining language elements, so I fear all of these would be fundamental. Worse, several of these constructs can only appear at top level, and so destroy the almost perfect lexical nestability enjoyed by ES3. If instead classes, for example, were defined purely by syntactic expansion to the constructs in ES3.1, then classes would inherit the lexical nestability of the constructs they expand into. Even Java's classes are lexically nestable! The namespace mechanism seems motivated by a failure to appreciate the power available by modest extensions of simple lambda abstraction. ES3 already provides some of the features for supporting such modest extensions: Several libraries (such as YUI) already use naming paths such as foo.bar.baz. This is supported by ES3's lexical scoping combined with its extensible records and its property lookup notation. Why should we prefer foo::bar::baz? ES3 already suffers from having two bottom values -- null and undefined -- with no general consensus of when one should use which. How are we to regard mixed naming paths such as foo.bar::baz? When should one use a record as a naming container vs a namespace? What is gained by having two mechanisms? I could go on and on about ES4's types gone
Re: ES4 draft: Object
On Mon, 10 Mar 2008, Waldemar Horwat wrote: intrinsic function propertyIsEnumerable(name: EnumerableId, flag: (boolean|undefined) = undefined): boolean I too find the second parameter here abhorrent. Please find another way to solve it (Brendan's namespace idea maybe) or remove this feature altogether. I believe what Waldemar is saying is that the method has a name that implies that it is a getter, but that the proposal has it working as a setter. This has a number of disadvantages. Primarily, it is unintuitive for authors. This makes code maintenance significantly more complicated, as readers of code tend to assume that getters cannot have side effects. This leads directly to bugs. We should design ES4 in a way that someone who is experienced with other programming languages, but who has never learnt ES4, can by and large correctly guess what any arbitrary ES4 code is doing. In this particular case, we have failed to achieve that. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.' ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: On Mar 8, 2008, at 1:16 PM, Yuh-Ruey Chen wrote: But doesn't DontEnum still have to be there for ES3 objects? How else would you prevent the enumeration of ES3 builtin methods, e.g. Object.prototype.toString()? Or is there some more open namespace magic that I'm unware of? ES3 code can't detect namespaces, so arguably shouldn't care if we were to implement DontEnum using an open namespace. But this could be a problem for mixed ES3 and ES4 scenarios where the ES4 code does introspect via Name objects and is surprised to find ES3 objects with qualified property names. I'm talking about how the enumerability (or lack thereof) of Object.prototype.* are determined. Or are prototype methods also not enumerable by default like fixtures? Let me get this straight. The rules of enumerability are: 1) If a property is a fixture, it's not enumerable. BTW, what exactly is a fixture? Does this included ES3-style prototype methods? And would it be possible to init a fixture to be enumerable? 2) If a property is not in the public namespace, it's not enumerable. 3) Otherwise, it is enumerable. 4) No hidden DontEnum attribute. Are we trying to simplify this to the last three rules using some namespace voodoo to handle the fixture rule? I'm confused. Well, I think the only overlap is that public-in-class-context methods (or any method really) default to be non-public in terms of enumerability Is that the right design? dynamic class C { public var fixture; function C() { this.expando = 42; } } for (var i in new C) intrinsic::print(i); wouldn't you expect to see expando printed? Is it printed because the default namespace for expando is the public-default one? I believe it is not, in the current proposal and the RI. Rather, each class or package gets a nonce-named public namespace, different from every other such per-class or per-package public. IIRC package trumps class -- classes within a package share the package's nonce-named public namespace (Jeff, Lars, please correct me if I'm wrong). I meant non-expando vars and methods defined within the class, whatever the terminology is used (I see 'fixture' thrown around everywhere), are not enumerable. So yes, expando should be printed. And the RI does print it, so I'm not sure what you're talking about. Are you saying that each property is defined in a class-specific public namespace, and therefore does not get enumerated? I would say that expando properties should be defined in the global public namespace, so that they would be enumerated. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of zwetan Sent: 7. mars 2008 19:28 To: Brendan Eich Cc: es4-discuss@mozilla.org es4-discuss; Yuh-Ruey Chen; Erik Arvidsson Subject: Re: ES4 draft: Object why not have a global utility function, maybe in the magic namespace The magic namespace (like informational and helper) is a specification artifact, it does not exist in an implementation. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On 2008-03-07, at 22:43 EST, Brendan Eich wrote: The goal is to find the minimum amount of mutating meta-programming sharpness for this make certain properties non-enumerable tool. If it can be done with a one-time namespace qualification step, that wins. A few comments: I am confused. I guess I thought everything was in a namespace, just that there is a default namespace that things with no explicit namespace are in. Which makes me wonder how the namespace/not- enumerable proposal will really work. I think it is absolutely right that fixtures are not enumerable. And a bug that things that would have been fixtures if you had them are enumerable in es3. It seems to me that for-in/enumerability are all about Maps, maybe now that we have Maps (and classes with fixtures), we don't have to worry about enumerability in Objects so much. Finally, for debugging, I would want to be able to find all the properties of an object, non-enumerable and fixtures included. Will there be a way to introspect like that? ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of P T Withington Sent: 8. mars 2008 10:10 To: Brendan Eich Cc: zwetan; es4-discuss@mozilla.org es4-discuss; Yuh-Ruey Chen; Erik Arvidsson Subject: Re: ES4 draft: Object On 2008-03-07, at 22:43 EST, Brendan Eich wrote: The goal is to find the minimum amount of mutating meta-programming sharpness for this make certain properties non-enumerable tool. If it can be done with a one-time namespace qualification step, that wins. A few comments: I am confused. I guess I thought everything was in a namespace, just that there is a default namespace that things with no explicit namespace are in. Which makes me wonder how the namespace/not- enumerable proposal will really work. Some namespaces are public and distinguished thereby, properties in these namespaces would be enumerated. One of the public namespaces is the default namespace that things with no explicit namespace are in. (We're still fine-tuning the details of that.) Finally, for debugging, I would want to be able to find all the properties of an object, non-enumerable and fixtures included. Will there be a way to introspect like that? Not certain yet. Being able to just do it is a security concern if you think namespaces are in part about hiding access to private data. (Debugging facilities in the language are not a good idea if there is any chance at all that some of the code in a program may be hostile. We have to make a choice about that when we write the spec for the reflection mechanism.) --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: - Users may think this dontenum namespace is magical and yet another thing to keep in mind, when it really just relies on the namespace trick you mentioned. With the introduction of classes and namespaces, the rules of enumerability are already more complex, so this adds to the cognitive load slightly. Slightly, but it takes away the magic DontEnum attribute, formerly hogged by the specification and magic predefined objects. But doesn't DontEnum still have to be there for ES3 objects? How else would you prevent the enumeration of ES3 builtin methods, e.g. Object.prototype.toString()? Or is there some more open namespace magic that I'm unware of? BTW, if setPropertyIsEnumerable() is added, would it be possible to make fixtures enumerable? Enumerability is orthogonal to static analysis (which fixtures are meant to help with), so I don't see why not. This gets to the heart of the public vs. public-in-context-of-class- or-package issue. We need to sort this out to find out exactly how orthogonal enumerability is, as well as decide how flexible it should be. Well, I think the only overlap is that public-in-class-context methods (or any method really) default to be non-public in terms of enumerability - The name sucks :p Indeed. How about 'hidden' or 'nonEnumerable'? I'd prefer 'hidden', since 'nonEnumerable' implies more strongly that a prop needs to be in that namespace to not be enumerable, when that's not the case. Which gets me back to the cognitive load issue. Even with a name like 'hidden', they may think they may have to do some funky syntax like |obj.hidden::other_ns::prop| do hide a prop in another namespace. While we're on the topic of namespaces, I read in the ES4 overview: In addition, the names internal, public, protected, and private denote namespace values, but the values depend on the context of the use. As the wiki doesn't talk about this, and the online spec is inaccessible/outdated, can you elaborate on this? I wonder if 'private' could be used somehow for enumerability. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Garrett Smith wrote: obj = {dontenum length: 10} ); vs. obj = {length: 10}; obj.propertyIsEnumerable(length, false); Which is more ugly? Garrett Of course I prefere the first line but these two cases are different. I wonder if a builtin method will not cause more problems instead of avoiding them. What I mean is what is the expected behaviour in this case? Object.prototype.propertyIsEnumerable(length, false); // some stuff ... and then ... Object.prototype.propertyIsEnumerable(length, true); I think Object.prototype is the perfect case scenario where this built in method could cause more chaos than ever, while the dontenum in declaration makes sense specially when I write my own object and/or prototoype and I would like that no one will be able to change my not enumerable property. So I guess built in method is error/conflicts/problems prone while the first one is quite safer (and at the same time, I do like to know if others add some Object.prototype, both to avoid conflicts, problems, and errors) These are only my 5 cents to this interesting discussion. Kind Regards -- - Zend Certified Engineer ActionScript 2.0 Certified Developer Web 2.0 Specialist - Cel. +39 338 7621067 ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Brendan Eich wrote: To avoid injecting a public name into Object.prototype, we could put a new setPropertyIsEnumerable (yechh) name in the __ES4__ namespace. Then there's no breaking change. We do this already, of course, but not for property attribute fiddling. Since enumerability only applies to for-in, how about the iterator namespace? Object.prototype.iterator::setPropertyIsEnumerable(prop, enable). For consistency, you could also have Object.prototype.iterator::isPropertyEnumerable(prop) which delegates to Object.prototype.isPropertyEnumerable(prop). An alternative we've discussed, which Ian also brought up: add a keyword for declaring DontEnum properties. This dontenum modifier can be used in addition to the method for convenience - it would make class declarations cleaner. But despite that, I think dontenum is inelegant. Its only effect would be on the default enumerator, which is only one iterator, and AFAIK is not special at all. IMO, it isn't worth the bloat. If there was a way to define such modifiers within script, then I think the dontenum modifier would be nice. If such a capability is planned for a future ES edition, then I think dontenum is fine. -Yuh-Ruey Chen ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mar 7, 2008, at 1:14 PM, Yuh-Ruey Chen wrote: Brendan Eich wrote: To avoid injecting a public name into Object.prototype, we could put a new setPropertyIsEnumerable (yechh) name in the __ES4__ namespace. Then there's no breaking change. We do this already, of course, but not for property attribute fiddling. Since enumerability only applies to for-in, how about the iterator namespace? Good suggestion. Here's something I wrote a while ago (minor edits to update for context) that attempts to subsume enumerability under namespacing: If we say enumeration considers only public non-DontEnum properties, then DontEnum is always true for namespaced props. Mixing DontEnum magic into the obj = {var dontDel: 42, const RO_AND_DD: foo} idea is wrong -- these should be public and enumerable as other properties in object initialisers are, by default. But we are *this* close to eliminating an independent DontEnum attribute. The problem is how to express public + DontEnum. Suppose we had a predefined, open namespace, say dontenum (surely not the best name). If you write obj = {dontenum::cant_see_me: 33} then for (i in obj) print(i) shows nothing. But obj.cant_see_me works, because dontenum is always open. No more need for an orthogonal DontEnum attribute. Instead of obj.propertyIsEnumerable('i_want_to_hide', false) users would just say obj.dontenum::i_want_to_hide = ... (typically obj is a prototype object and ... is a function). The setter mode (second boolean arg) of propertyIsEnumerable is ugly (everyone says so, no one denies). It's arguably hard to use (because verbose). It's racy for users who have to call it after creating a property (there's a window in which the property is enumerable -- not a threading race per se, more low-level bug habitat and needless worry). It's a burden on implementations that want immutable attributes for props. On the down side, you can't just add obj.dontenum::foo = function () {...} to ES3 code that runs in ES3-only browsers, as you could with the propertyIsEnumerable hack. We should in any case design for the long run. Note that any namespace would hide a property from enumeration; dontenum is not magic in that sense, only in that it is predefined and open by default (again, its name is a strawman). For the long run, rationalizing dontenum via namespaces seems good to me. Object.prototype.iterator::setPropertyIsEnumerable(prop, enable). For consistency, you could also have Object.prototype.iterator::isPropertyEnumerable(prop) which delegates to Object.prototype.isPropertyEnumerable(prop). Clever relocation of is in the predicate names ;-). We're probably stuck with propertyIsEnumerable. An alternative we've discussed, which Ian also brought up: add a keyword for declaring DontEnum properties. This dontenum modifier can be used in addition to the method for convenience - it would make class declarations cleaner. True of a namespace already, note. But despite that, I think dontenum is inelegant. Its only effect would be on the default enumerator, which is only one iterator, and AFAIK is not special at all. IMO, it isn't worth the bloat. If there was a way to define such modifiers within script, then I think the dontenum modifier would be nice. If such a capability is planned for a future ES edition, then I think dontenum is fine. What do you think of the only-public-properties-are-enumeable idea? Obvious problem to be solved: public means several things: no namespace (backward compatible) vs. public in this package or class. We should discuss this more. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Brendan Eich Sent: 5. mars 2008 19:19 To: Erik Arvidsson Cc: es4-discuss@mozilla.org es4-discuss Subject: Re: ES4 draft: Object To avoid injecting a public name into Object.prototype, we could put a new setPropertyIsEnumerable (yechh) name in the __ES4__ namespace. Then there's no breaking change. We do this already, of course, but not for property attribute fiddling. Right, it comes up from time to time. Using __ES4__ here would set a precedent that might not be the best. An alternative we've discussed, which Ian also brought up: add a keyword for declaring DontEnum properties. It turns out the full combination of property attributes is not interesting. We have const for DontDelete+ReadOnly (ReadOnly without DontDelete guarantees nothing, is worthless) including in object initialisers: obj = {const PI: 22/7}; // Ohio legislature once so legislated We have (I hope it got filed) a ticket asking for DontDelete by itself via var in object initialisers: obj = {var x: mutate me, but you can't delete me!} Not filed in the Trac to my knowledge, but not forgotten. DontEnum is orthogonal but clear by default for binding and assigning forms in ES3. It is set for built-ins, generally speaking (some odd exceptions that I recall in the Error objects -- I was not around much for ES3, although I did the work in Netscape 4 that fed into it!). The text of E262-3 does not reveal anything unusual about the Error objects, as far as I can see. So, rather than add an ugly dontenum keyword that would be seldom used, the group preferred a built-in method. But this may have been a minor mistake. For those interested, here's the full rationale as I remember it: Besides avoiding adding anything with a plain name to Object.prototype, the appeal (if you can call it that) of extending propertyIsEnumerable with an optional second argument lies in the ability to call it with two arguments in an ES3 implementation. That won't have any effect, but it won't break callin code in ES3 implementations either. Thus Ajax libraries such as Prototype (if it still does this) could add calls to turn off enumerability of properties the library sets on standard prototypes, and then those properties would disappear from for-in loop enumerations in ES4 implementations. Mainly we do not expect the ability to turn off enumeration of a given property to be a frequent programmer task, so we did not want to add a new method if we could piggy-back on an existing Object.prototype method. For library authors, we wanted something that failed soft in ES3. And yeah, we knew it was ugly, but propertyIsEnumerable is already ugly already. Also, a declarative form is of uncertain value, since the object that receives the new property whose attr must be set, already exists. Thus if there is some sort of new keyword form it needs to be associated with the assignment somehow. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED] On Behalf Of Brendan Eich Sent: 6. mars 2008 18:04 To: Garrett Smith Cc: es4-discuss@mozilla.org es4-discuss; Erik Arvidsson Subject: Re: ES4 draft: Object Remember that fixtures declared in classes are not enumerable, which is the right default for all the native (built-in is better, since these can be and are increasingly self-hosted) objects' properties. Agreed native is misnomer now. I've adopted predefined (or pre-defined depending on my mood) instead of built-in but this is something that will be cleaned up in the editorial process pretty soon. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
ES4 draft: Object
This is the draft for the Object class. It's very similar to the Object object in ES3, the only addition (to my knowledge) is the extra parameter to propertyIsEnumerable. And of course the specification formalism is new. Please comment. --lars Title: The class "Object" The class Object FILE: spec/library/Object.html DRAFT STATUS: DRAFT 1 - 2008-03-05 REVIEWED AGAINST ES3: YES REVIEWED AGAINST ERRATA:YES REVIEWED AGAINST BASE DOC: YES REVIEWED AGAINST PROPOSALS: YES REVIEWED AGAINST CODE: YES The class Object is a dynamic non-final class that does not subclass any other objects: it is the root of the class hierarchy. All values in ECMAScript except undefined and null are instances of the class Object or one of its subclasses. NOTE Host objects may not be instances of Object or its subclasses, but must to some extent behave as if they are (see Host objects). Synopsis The class Object provides this interface: public dynamic class Object { public function Object(value=undefined) static meta function invoke(value=undefined) static public const length = 1 intrinsic function toString() : string intrinsic function toLocaleString() : string intrinsic function valueOf() : Object intrinsic function hasOwnProperty(name: EnumerableId): boolean intrinsic function isPrototypeOf(obj): boolean intrinsic function propertyIsEnumerable(name: EnumerableId, flag: (boolean|undefined) = undefined): boolean } The Object prototype object provides these direct properties: toString: function () , toLocaleString: function () , valueOf: function () , hasOwnProperty: function (V) , isPrototypeOf:function (V) , propertyIsEnumerable: function (name, flag=undefined) , The Object prototype object is itself an instance of the class Object, with the exception that the value of its [[Prototype]] property is null. Methods on the Object class object newObject(value=) Description When the Object constructor is called with an argument value (defaulting to undefined) as part of a new _expression_, it transforms the value to an object in a way that depends on the type of value. Returns The Object constructor returns an object (an instance of Object or one of its subclasses, or a host object). NOTE The Object constructor is the only constructor function defined on a class in the language whose result may be a value of a different class than the one in which the constructor is defined. Implementation The Object constructor can't be expressed as a regular ECMAScript constructor. Instead it is presented below as a helper function makeObject that the ECMAScript implementation will invoke when it evaluates new Object. The helper function makeObject only is invoked on native ECMAScript values. If new Object is evaluated on a host object, then actions are taken and a result is returned in an implementation dependent manner that may depend on the host object. helper function makeObject(value=undefined) { switch type (value) { case (s: string) { return new String(s); } case (b: boolean) { return new Boolean(b); } case (n: (int|uint|double|decimal)) { return new Number(n); } case (x: (null|undefined)) { return magic::createObject(); } case (o: Object) { return o; } } } Object(value=) Description When the Object class object is called as a function with zero or one arguments it performs a type conversion. Returns It returns the converted value. Implementation static meta function invoke(value=undefined) new Object(value); Methods on Object instances intrinsic::toString() Description The intrinsic toString method converts the this object to a string. Returns The intrinsic toString method returns the concatenation of "[", "object", the class name of the object, and "]". Implementation intrinsic function toString() : string "[object " + magic::getClassName(this) + "]"; The function magic::getClassName extracts the class name from the object. See magic:getClassName. intrinsic::toLocaleString() Description The intrinsic toLocaleString method calls the public toString method on the this object. NOTE This method is provided to give all objects a generic toLocaleString interface, even though not all may use it. Currently, Array, Number, and Date provide their own locale-sensitive toLocaleString methods. NOTE The first parameter to this function is likely to be used in a future version of this standard; it is recommended that implementations do not use this parameter position for anything else. Returns The intrinsic toLocaleString method returns a string. Implementation intrinsic function toLocaleString() : string this.toString(); intrinsic::valueOf() Description The intrinsic valueOf method returns its
Re: ES4 draft: Object
We (Google) find setting the [[DontEnum]] flag with propertyIsEnumerable(name, flag) to be quite ugly. I can't find any references to why the setter was tagged along onto the getter in this way? Is there a reason why we don't want setPropertyIsEnumerable(name, flag) instead of overloading the getter? 2008/3/5 Lars Hansen [EMAIL PROTECTED]: This is the draft for the Object class. It's very similar to the Object object in ES3, the only addition (to my knowledge) is the extra parameter to propertyIsEnumerable. And of course the specification formalism is new. Please comment. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss -- erik ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
On Mar 5, 2008, at 5:04 PM, Erik Arvidsson wrote: We (Google) find setting the [[DontEnum]] flag with propertyIsEnumerable(name, flag) to be quite ugly. I can't find any references to why the setter was tagged along onto the getter in this way? Is there a reason why we don't want setPropertyIsEnumerable(name, flag) instead of overloading the getter? Adding any properties to Object.prototype at this point is difficult. You may break object-detection tests. Is it worth the risk? /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
RE: ES4 draft: Object
-Original Message- From: Erik Arvidsson [mailto:[EMAIL PROTECTED] Sent: 5. mars 2008 17:04 To: Lars Hansen Cc: es4-discuss@mozilla.org Subject: Re: ES4 draft: Object We (Google) find setting the [[DontEnum]] flag with propertyIsEnumerable(name, flag) to be quite ugly. Can't argue with that. I can't find any references to why the setter was tagged along onto the getter in this way? Is there a reason why we don't want setPropertyIsEnumerable(name, flag) instead of overloading the getter? It was felt, and I think it is still felt, that it is dangerous to introduce new names on the Object prototype, because the risk of clashes with code on the web is too great. As the problem that is solved by the overloading is really worth solving, the ugliness of the solution seemed to be acceptable. --lars 2008/3/5 Lars Hansen [EMAIL PROTECTED]: This is the draft for the Object class. It's very similar to the Object object in ES3, the only addition (to my knowledge) is the extra parameter to propertyIsEnumerable. And of course the specification formalism is new. Please comment. --lars ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss -- erik ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
I'm not sure it is such a big issue since the new method would be [[DontEnum]] but I'm willing to let this rest. The reason why I don't think it is that a big risk is that a lot of people still use Array instead of Object for associative arrays and I don't think adding the array extras introduced any problems. Brendan, did you get any bug reports on Spidermonkey when array extras was added? On Wed, Mar 5, 2008 at 17:19, Brendan Eich [EMAIL PROTECTED] wrote: On Mar 5, 2008, at 5:04 PM, Erik Arvidsson wrote: We (Google) find setting the [[DontEnum]] flag with propertyIsEnumerable(name, flag) to be quite ugly. I can't find any references to why the setter was tagged along onto the getter in this way? Is there a reason why we don't want setPropertyIsEnumerable(name, flag) instead of overloading the getter? Adding any properties to Object.prototype at this point is difficult. You may break object-detection tests. Is it worth the risk? /be -- erik ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss
Re: ES4 draft: Object
Hixie argued strongly on IRC today for something that does not overload set with get -- this seems to be the heart of the ugly objection, although there are other things to dislike about both the form and function of propertyIsEnumerable (it does not consider prototypes, as for-in does; its name is overlong and it violates standard naming conventions for is method). To avoid injecting a public name into Object.prototype, we could put a new setPropertyIsEnumerable (yechh) name in the __ES4__ namespace. Then there's no breaking change. We do this already, of course, but not for property attribute fiddling. An alternative we've discussed, which Ian also brought up: add a keyword for declaring DontEnum properties. It turns out the full combination of property attributes is not interesting. We have const for DontDelete+ReadOnly (ReadOnly without DontDelete guarantees nothing, is worthless) including in object initialisers: obj = {const PI: 22/7}; // Ohio legislature once so legislated We have (I hope it got filed) a ticket asking for DontDelete by itself via var in object initialisers: obj = {var x: mutate me, but you can't delete me!} DontEnum is orthogonal but clear by default for binding and assigning forms in ES3. It is set for built-ins, generally speaking (some odd exceptions that I recall in the Error objects -- I was not around much for ES3, although I did the work in Netscape 4 that fed into it!). So, rather than add an ugly dontenum keyword that would be seldom used, the group preferred a built-in method. But this may have been a minor mistake. For those interested, here's the full rationale as I remember it: Besides avoiding adding anything with a plain name to Object.prototype, the appeal (if you can call it that) of extending propertyIsEnumerable with an optional second argument lies in the ability to call it with two arguments in an ES3 implementation. That won't have any effect, but it won't break callin code in ES3 implementations either. Thus Ajax libraries such as Prototype (if it still does this) could add calls to turn off enumerability of properties the library sets on standard prototypes, and then those properties would disappear from for-in loop enumerations in ES4 implementations. Mainly we do not expect the ability to turn off enumeration of a given property to be a frequent programmer task, so we did not want to add a new method if we could piggy-back on an existing Object.prototype method. For library authors, we wanted something that failed soft in ES3. And yeah, we knew it was ugly, but propertyIsEnumerable is already ugly already. /be ___ Es4-discuss mailing list Es4-discuss@mozilla.org https://mail.mozilla.org/listinfo/es4-discuss