Proposal: Concise instance initialisation
this.c:= 1 looks like an error. If the intent was to set the "c" property to a constant, it should not be a function' parameter. If, as I understood, you have set a default value for the c parameter, what if you didn't specify that value? I think it shows that the current 'readonly' syntax (aka :=) should be reconsiderated, because it's the only one that's postfix (and the only one who need an equality symbol after it, which makes it difficult to exted its use to other locations, as this exemple puts in light).
PROPOSAL: Prefix readonly flag (or postfix everything)
The problem I see is that it still may be non-extendable to other places (i.e. traditionnal assignations) because the ! symbol is already used as the "NOT" operator.
Another option would be to use only two symbols (I used õ and ñ here, but we could imagine using something different) and using them as flags :
ñ not enumerable õñ not writable õõñ not configurable õññ not writable AND not configurable
PROPOSAL: Extension to all assignations (here using õñ flags)
function setParent(a) {
a._hasParent ñññ= true;
a.parent õññ= this;
}
function ReadOnlyPoint(this.x õññ, this.y õññ) {} // will be rare in
true code
function setTag(obj, value) { obj.__tag ñ= value; }
function getTag(obj) { return obj.__tag; }
Another beautiful combination could be ~ and :
function setParent(a) {
a._hasParent ~~~= true;
a.parent :~~= this;
}
function ReadOnlyPoint(this.x :~~, this.y :~~) {} // will be rare in
true code
function setTag(obj, value) { obj.__tag ~= value; }
function getTag(obj) { return obj.__tag; }
Please note that in the case of traditionnal assignations, the ! could be used because the expression before an assignation symbol should not contains a NOT operator anyway. It could just be confusing to see things like "!#obj.boolProperty=!objToCopy.boolProperty" while "obj.boolProperty õññ= !objToCopy.boolProperty" seems clearer (to me, at least). At least, it makes it clear that it's not a simple assignation but a more complex one.
(Maybe a more global remark:) I know the current mainstream seems to be "please, less characters to type", but I'm sincerely under the impression that the more we go in that direction the less clear the syntax becomes and the more possible confusions are introduced. Maybe should we include in every proposal more than one flavor (and a least a verbose one) so that the different specials chars don't overlap between all proposals. At the end, the comitee would decide which proposals will get a short syntax and which will get a longer one, in order to avoid different meaning for a same keyword (or symbol) when it can be confusing (and to maximise the usage of the short syntax in the most promising proposals while less used pattern would get longer syntax).
-----Message d'origine---
On Sat, May 21, 2011 at 5:11 AM, François REMY <fremycompany_pub at yahoo.fr> wrote:
this.c:= 1 looks like an error. If the intent was to set the "c" property to a constant, it should not be a function' parameter. If, as I understood, you have set a default value for the c parameter, what if you didn't specify that value?
Then c would be defaulted to 1.
I think it shows that the current 'readonly' syntax (aka :=) should be reconsiderated, because it's the only one that's postfix (and the only one who need an equality symbol after it, which makes it difficult to exted its use to other locations, as this exemple puts in light).
PROPOSAL: Prefix readonly flag (or postfix everything)
Yes, I think they should all be prefix. I think the non-writable mark is currently next to the value since they are both data-property-only attributes, however, it would be easy to just disallow the non-writable mark before getters and setters. We would need a different non-writable mark though since = can already take an assignment expression as its right operand, thus this wouldn't work:
a =b.c = d
I think we should switch to these marks:
for non-configurable since it maps to frozen which # represents for
records, tuples etc. ! for non-writable, the lighter weight compared to # matches the lighter restriction compared to non-configurable ~ for non-enumerable since ~ maps a set of bits into a subset, and enumeration maps a set of properties into a subset
Postfix would actually look like |a.b = c#!~| which would require a "no line terminator here" rule, and I don't think infix would work
a.b #!~= c // nice :) a.b != c // already taken :( var a = {get b(){return c;}} // no RHS, where do I put the marks ?
Also, the current infix writable mark does not compose with "Implicit property initialization expressions" [1] as noted in [2]. Using a prefix fixes this:
let a = {!b}
The problem I see is that it still may be non-extendable to other places (i.e. traditionnal assignations) because the ! symbol is already used as the "NOT" operator.
I don't think that's an issue, these all look backward compatible to me:
!a.b = c !a[b] = c ~a.b = c ~a.b += c #a.b = c #!~ a[b] *= c
Another option would be to use only two symbols (I used õ and ñ here, but we could imagine using something different) and using them as flags :
ñ not enumerable õñ not writable õõñ not configurable õññ not writable AND not configurable
I think we are restricted to using type-able ASCII characters for surface syntax.
Also, I prefer a character mapping to an index mapping because:
Characters can be chosen mnemonically (as I tried to do above), index order is difficult to remember Less verbose as seen by your last 3 examples. More visually distinct.
PROPOSAL: Extension to all assignations (here using õñ flags)
function setParent(a) { a._hasParent ñññ= true; a.parent õññ= this; }
function ReadOnlyPoint(this.x õññ, this.y õññ) {} // will be rare in true code
function setTag(obj, value) { obj.__tag ñ= value; }
function getTag(obj) { return obj.__tag; }
Another beautiful combination could be ~ and :
function setParent(a) { a._hasParent ~
= true; a.parent := this; }function ReadOnlyPoint(this.x :
, this.y :) {} // will be rare in true codefunction setTag(obj, value) { obj.__tag ~= value; }
function getTag(obj) { return obj.__tag; }
Please note that in the case of traditionnal assignations, the ! could be used because the expression before an assignation symbol should not contains a NOT operator anyway. It could just be confusing to see things like "!#obj.boolProperty=!objToCopy.boolProperty" while "obj.boolProperty õññ= !objToCopy.boolProperty" seems clearer (to me, at least). At least, it makes it clear that it's not a simple assignation but a more complex one.
To summarize, I think prefixing with # ~ and ! as above would work across the board for all types of property assignment.
Also, if destructuring were then extended to allow the individual LHS's to be property references rather than just Identifiers, something like this would work:
var [a, #~this.b, !this.c] = arguments;
Then, if destructuring were integrated with parameter lists as I suggested in "Parameter lists as arguments destructuring sugar" [3], the "concise instance initialization" use case could be gotten for free:
function A (a, #~this.b, !this.c){ foo(a); }
(Maybe a more global remark:) I know the current mainstream seems to be "please, less characters to type", but I'm sincerely under the impression that the more we go in that direction the less clear the syntax becomes and the more possible confusions are introduced. Maybe should we include in every proposal more than one flavor (and a least a verbose one) so that the different specials chars don't overlap between all proposals. At the end, the comitee would decide which proposals will get a short syntax and which will get a longer one, in order to avoid different meaning for a same keyword (or symbol) when it can be confusing (and to maximise the usage of the short syntax in the most promising proposals while less used pattern would get longer syntax).
I agree that we should be very careful when adding syntax sugar, however there are clearly cases where it makes sense, and I think this could be one of them. Also, I think it should be all or nothing, if we provide sugar for initializing property descriptor attributes, we should also provide it for modifying them or adding new properties as that is likely just as common of a use case.
-----Message d'origine----- From: Sean Eagan Sent: Saturday, May 21, 2011 10:10 AM To: es-discuss Subject: Proposal: Concise instance initialisation
Summary:
Update "Object Literal Extensions" [1] to integrate with constructor parameters for concise instance initialization.
Details:
function f (a, !~this.b, this.c:= 1) { g(a); }
// results in f's [[Construct]] ( but not [[Call]] ) behaving like:
function f (a, b, c = 1) { Object.defineProperty(this, "b", {configurable: false, enumerable: false, writable; true, value: b}; Object.defineProperty(this, "c", {configurable: true, enumerable: true, writable; false, value: c}; g(a); }
Grammar changes to [1] :
FormalParameter : FormalParameterPrefixOpt Identifier FormalParameterInitialiserOpt // possibly integrate with destructuring and/or rest parameters as well
FormalParameterPrefix : PropertyPrefixOpt thisOpt . // "this" is optional
FormalParameterInitialiser : :Opt Initialiser
[1] strawman:basic_object_literal_extensions
Cheers, Sean Eagan
es-discuss mailing list es-discuss at mozilla.org, mail.mozilla.org/listinfo/es-discuss
[1] strawman:object_initialiser_shorthand [2] strawman:basic_object_literal_extensions [3] esdiscuss/2011-April/013570
I fully agree with your remarks. Infix flags to the "=" operator causes issues that are difficult to solve. Let's go for a "evertything prefix", then.
-----Message d'origine---
Please excuse me, I'm just looking for clarification - thanks in advance:
Also, the current infix writable mark does not compose with "Implicit property initialization expressions" [1] as noted in [2]. Using a prefix fixes this:
let a = {!b}
This conflicts with the existing:
var foo = "bar"; {foo} // "bar" {!foo} // false
I don't think that's an issue, these all look backward compatible to me:
!a.b = c !a[b] = c ~a.b = c ~a.b += c #a.b = c #!~ a[b] *= c
Ignoring the lines prefixed "#"; all of these are currently invalid left hand assignment reference errors. Take away the assignments and the first two are negations, the second two bitwise not operations. So I'm wondering if they become "backward compatible" by simply becoming allowed, parsable syntax?
Also, if destructuring were then extended to allow the individual LHS's to be property references rather than just Identifiers, something like this would work:
var [a, #~this.b, !this.c] = arguments;
Forgive me if I've misunderstood, assuming "#~" is somehow allowable, the third would still be negated with logical not, right?
Again, thanks for the clarification.
On Mon, May 23, 2011 at 4:44 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
Please excuse me, I'm just looking for clarification - thanks in advance:
Also, the current infix writable mark does not compose with "Implicit property initialization expressions" [1] as noted in [2]. Using a prefix fixes this:
let a = {!b}
This conflicts with the existing: var foo = "bar"; {foo} // "bar" {!foo} // false
No, just because |{!b}| is current syntax, doesn't mean that |var a = {!b}| is.
I don't think that's an issue, these all look backward compatible to me:
!a.b = c !a[b] = c ~a.b = c ~a.b += c #a.b = c #!~ a[b] *= c
Ignoring the lines prefixed "#"; all of these are currently invalid left hand assignment reference errors. Take away the assignments and the first two are negations, the second two bitwise not operations. So I'm wondering if they become "backward compatible" by simply becoming allowed, parsable syntax?
Yes, I am proposing new syntax and to my knowledge it is "backward compatible" which means that it does not change the semantics of any existing syntax.
Also, if destructuring were then extended to allow the individual LHS's to be property references rather than just Identifiers, something like this would work:
var [a, #~this.b, !this.c] = arguments;
Forgive me if I've misunderstood, assuming "#~" is somehow allowable, the third would still be negated with logical not, right?
I'm proposing to extend destructuring [1] to allow arbitrary LValues (see [1]) rather than just Identifiers even when the destructuring pattern is prefixed with a binding modifier ("var", "let", or "const") and only use the binding modifier on the LValues that are Identifiers. So, starting from a function definition, here is essentially how the desugaring would unfold:
function A (a, #~this.b, !this.c){ foo(a); }
// ->
function A (){ var [a, #~this.b, !this.c] = arguments; foo(a); }
// ->
function A (){ var a = arguments[0]; #~this.b = arguments[1]; !this.c = arguments[2]; foo(a); }
// ->
function A (){ var a = arguments[0]; Object.defineProperty(this, "b", {configurable: false, enumerable: false, writable: true, arguments[1]}) Object.defineProperty(this, "c", {configurable: true, enumerable: true, writable: false, arguments[2]}) foo(a); }
Again, thanks for the clarification. Rick
Thanks, Sean Eagan
On Tue, May 24, 2011 at 9:02 AM, Sean Eagan <seaneagan1 at gmail.com> wrote:
// ->
function A (){ var a = arguments[0]; Object.defineProperty(this, "b", {configurable: false, enumerable: false, writable: true, arguments[1]}) Object.defineProperty(this, "c", {configurable: true, enumerable: true, writable: false, arguments[2]}) foo(a); }
Sorry, that should have been:
function A (){ var a = arguments[0]; Object.defineProperty(this, "b", {configurable: false, enumerable: false, writable: true, value: arguments[1]}) Object.defineProperty(this, "c", {configurable: true, enumerable: true, writable: false, value: arguments[2]}) foo(a); }
On May 24, 2011, at 7:02 AM, Sean Eagan wrote:
This conflicts with the existing: var foo = "bar"; {foo} // "bar" {!foo} // false
No, just because |{!b}| is current syntax, doesn't mean that |var a = {!b}| is.
I've been working on syntax lately, and based on that work, I think this goes too far. It requires splitting the grammar in a way that needs greater parsing power than LR(1), e.g. GLR. Unlikely to get by TC39 and implementors.
It would be better to preclude the ! and ~ prefixes from being used with the {b} shorthand.
On Tue, May 24, 2011 at 9:10 AM, Brendan Eich <brendan at mozilla.com> wrote:
On May 24, 2011, at 7:02 AM, Sean Eagan wrote:
This conflicts with the existing: var foo = "bar"; {foo} // "bar" {!foo} // false
No, just because |{!b}| is current syntax, doesn't mean that |var a = {!b}| is.
I've been working on syntax lately, and based on that work, I think this goes too far. It requires splitting the grammar in a way that needs greater parsing power than LR(1), e.g. GLR. Unlikely to get by TC39 and implementors.
It would be better to preclude the ! and ~ prefixes from being used with the {b} shorthand.
/be
I am definitely a grammar classification noob, so feel free to rake me over the coals on this if necessary, but how is :
var a = {!b};
... any more difficult to parse than ...
var a = {b};
... both {b} and {!b} and valid blocks, so it is equally as easy to determine that they are object literals instead, and once inside the object literal, everything should be peachy I would think.
Thanks, Sean Eagan
On May 24, 2011, at 7:37 AM, Sean Eagan wrote:
I am definitely a grammar classification noob, so feel free to rake me over the coals on this if necessary, but how is :
var a = {!b};
... any more difficult to parse than ...
var a = {b};
... both {b} and {!b} and valid blocks, so it is equally as easy to determine that they are object literals instead, and once inside the object literal, everything should be peachy I would think.
You're right, this would be unambiguous because a block can't initialize a var. The only interpretation is an expression, which with Allen's proposal combined with object intiialiser shorthand would parse {!b}.
So that's ok -- sorry for over-reacting.
What I'm concerned about is the attempt, precipitated by a suggestion from Doug Crockford, to parse block or object initialiser unambiguously. The key is restricting the syntax of labeled statements. If we find a way to do this, it won't extend to the object initialiser shorthand or variations like the one you propose. But it may be that we can't solve this riddle without GLR anyway, which could doom it.
On May 24, 2011, at 7:44 AM, Brendan Eich wrote:
You're right, this would be unambiguous because a block can't initialize a var. The only interpretation is an expression, which with Allen's proposal combined with object intiialiser shorthand would parse {!b}.
One more thing: {b} in expression context as shorthand for {b: b} is convenient. In destructuring context var {b} = c, e.g., is totally winning. But it breaks "alpha conversion" -- if you rename variables in a program with lexical scope, the result should be equivalent to the original program.
Ok, we can handle this by requiring long-hand expansion first:
... {b: b} ...
Then the {!b} form should expand to ... {!b: b} ... and that may be tolerable in the hoped-for block/object-literal disambiguation solution.
One thing that might be confusing: ... {!b} ... could be confused for ... {b: !b} .... People would learn, but the shorthand mixes uneasily with the retasking of ! and ~ from being unary expression operators to being property name prefixes.
Summary:
Update "Object Literal Extensions" [1] to integrate with constructor parameters for concise instance initialization.
Details:
function f (a, !~this.b, this.c:= 1) { g(a); }
// results in f's [[Construct]] ( but not [[Call]] ) behaving like:
function f (a, b, c = 1) { Object.defineProperty(this, "b", {configurable: false, enumerable: false, writable; true, value: b}; Object.defineProperty(this, "c", {configurable: true, enumerable: true, writable; false, value: c}; g(a); }
Grammar changes to [1] :
FormalParameter : FormalParameterPrefixOpt Identifier FormalParameterInitialiserOpt // possibly integrate with destructuring and/or rest parameters as well
FormalParameterPrefix : PropertyPrefixOpt thisOpt . // "this" is optional
FormalParameterInitialiser : :Opt Initialiser
[1] strawman:basic_object_literal_extensions