A shorthand for Object.defineProperty?
On Jun 20, 2011, at 3:43 AM, Axel Rauschmayer wrote:
Would it make sense to include a shorthand for calling Object.defineProperty() to object literals?
Possible benefits:
- Extensible, should other property attributes come up in the future
- Descriptive
- Might obviate the need to have a shorthand for "enumerable" (I usually ignore it and can’t think of any use cases)
=== Example ===
var Multiplier = { FACTOR :: { value: 3, writable: false },
Do not use :: -- it is wanted for strawman:guards (and used previously in E4X, ECMA-357).
Allen presented new syntax roughly as verbose at the March TC39 meeting. General reaction was "too verbose".
Wherefore the #!~ prefixes idea, now in harmony:object_literals -- the syntax there is definitely not final, BTW, but something like it is needed. I've argued we shouldn't try to be "half-verbose", and since ES5 has the very verbose functional API, object initialisers probably will go the other way.
Interesting insight, thanks. If defineProperties() was an instance method, we would have something like the following.
var Multiplier = { multiply: function (x) { return x * this.FACTOR; } }.defineProperties({ FACTOR: { value: 3, writable: false } });
That is, you use the object literal for when the defaults are OK and defineProperties() for special cases, without having to type "Object" and without having to repeat the object you want to add properties to. But with things still changing, this might be a case of YAGNI (introducing easy extensibility where it is never needed).
I keep thinking that something like Java annotations might also work here, especially as Python has adapted them successfully to its needs, via decorators: www.python.org/dev/peps/pep-0318
I would mainly use property attributes to declare a property as non-configurable and non-writable. That would be the analog to const for variables. Via decorators, one could introduce @const for this purpose.
Axel
On Jun 20, 2011, at 9:52 AM, Axel Rauschmayer wrote:
Interesting insight, thanks. If defineProperties() was an instance method, we would have something like the following.
var Multiplier = { multiply: function (x) { return x * this.FACTOR; } }.defineProperties({ FACTOR: { value: 3, writable: false } });
You could always get started via
Object.defineProperty(Object.prototype, 'defineProperties', {value: Object.defineProperties.bind(Object)});
I suppose.
That is, you use the object literal for when the defaults are OK and defineProperties() for special cases, without having to type "Object" and without having to repeat the object you want to add properties to. But with things still changing, this might be a case of YAGNI (introducing easy extensibility where it is never needed).
The above is a mix of Object.* verbosity with object literal conciseness. Not good to be between hell and heaven :-P.
I keep thinking that something like Java annotations might also work here, especially as Python has adapted them successfully to its needs, via decorators: www.python.org/dev/peps/pep-0318
I would mainly use property attributes to declare a property as non-configurable and non-writable. That would be the analog to const for variables. Via decorators, one could introduce @const for this purpose.
Decorators are in some folks' sights for Harmony, but not ES.next. However, they're still too verbose.
Decorators are in some folks' sights for Harmony, but not ES.next. However, they're still too verbose.
I like to distinguish between (1) encoding complexity for people who write code and (2) encoding complexity for people who read code. (2) is much more important than (1).
Examples:
- Perl optimizes (1), to the detriment of (2)
- Smalltalk optimizes (2).
- Semicolons fall into a similar category: As a reader, I’m used to punctuation and have an easier time reading code with semicolons, but they are obviously more to type.
I can usually handle a few special characters, but there is a threshold, after which I prefer full-blown keywords (again: those are parsed by the brain as a single token, so the cognitive load compared to single characters is about the same). If ES.next lands between Perl and Smalltalk, I’ll be very happy. ;-)
If one includes ES.next’s quasis, then ES.next might even be at the center of a triangle (Java, Smalltalk, Lisp) – which is a good thing.
On Mon, Jun 20, 2011 at 10:00 AM, Brendan Eich <brendan at mozilla.com> wrote:
On Jun 20, 2011, at 9:52 AM, Axel Rauschmayer wrote:
Interesting insight, thanks. If defineProperties() was an instance method, we would have something like the following.
var Multiplier = { multiply: function (x) { return x * this.FACTOR; } }.defineProperties({ FACTOR: { value: 3, writable: false } });
You could always get started via
Object.defineProperty(Object.prototype, 'defineProperties', {value: Object.defineProperties.bind(Object)});
The ".bind(Object)" above is unnecessary since Object.defineProperties does not use its this-binding.
On Jun 20, 2011, at 11:16 AM, Axel Rauschmayer wrote:
Decorators are in some folks' sights for Harmony, but not ES.next. However, they're still too verbose.
I like to distinguish between (1) encoding complexity for people who write code and (2) encoding complexity for people who read code. (2) is much more important than (1).
Examples:
- Perl optimizes (1), to the detriment of (2)
- Smalltalk optimizes (2).
- Semicolons fall into a similar category: As a reader, I’m used to punctuation and have an easier time reading code with semicolons, but they are obviously more to type.
It's not that simple. Semicolon-free languages come in several flavors: s-expression languages, significant-newline languages, other (generally expression languages). The significant newline fans make a good case for both ease of writing and ease of reading.
Anyway, my point is that decorators in front of functions and classes or other declarative forms work. In front of every property assignment in an object literal? Not so much.
It may be that we require @decorators to start on a new line (with leading horizontal space allowed, of course), in order to enable @ as an operator in expressions where [no LineTerminator here] would apply to the left of the @.
I can usually handle a few special characters, but there is a threshold, after which I prefer full-blown keywords (again: those are parsed by the brain as a single token, so the cognitive load compared to single characters is about the same). If ES.next lands between Perl and Smalltalk, I’ll be very happy. ;-)
Is there really any habitable land in between? That's the question.
What are the few special characters that you can handle, right now, as additions mooted for JS?
If one includes ES.next’s quasis, then ES.next might even be at the center of a triangle (Java, Smalltalk, Lisp) – which is a good thing.
Quasi-literals rule, and `` is the right quoting system given the characters left that can be easily typed and that don't ding readability.
We have <| but it is a bit contentious. No one has topped it, though, and a keyword instead seems to lose on both restricted-production and no-better-word-than-<| grounds.
Some find -> and => cryptic, but it's hard to say the only alternative is to stick to eight-letter 'function'. ('lambda' is not reserved and can't be used without breaking compatibility; and it's six letters.)
Some find block-lambdas with their Ruby- (and to a lesser extend Smalltalk-) inspired {||...} bracketing cryptic.
There are other options, but they all face genreric "too much line noise!" objections.
On Jun 20, 2011, at 11:22 AM, Mark S. Miller wrote:
The ".bind(Object)" above is unnecessary since Object.defineProperties does not use its this-binding.
Cool -- was playing it safe here, without checking the spec. Thanks,
Anyway, my point is that decorators in front of functions and classes or other declarative forms work. In front of every property assignment in an object literal? Not so much.
The defaults outlined in “Object Literal Extensions” should work well, I especially like the shorter syntax for methods. What other needs are there? @const (=non-configurable and non-writable) and @private? That would move things a little more into the direction of Java, but I wouldn’t mind that. A little more verbose, yes, but one would also immediately understand what is going on.
It may be that we require @decorators to start on a new line (with leading horizontal space allowed, of course), in order to enable @ as an operator in expressions where [no LineTerminator here] would apply to the left of the @.
That makes sense. I always format my code like this, anyway. Syntax coloring displays them in gray which greatly minimizes perceived clutter.
What are the few special characters that you can handle, right now, as additions mooted for JS?
I can handle everything except for some of the proposed object literal shorthands (see code at the bottom of this email). Read on.
Quasi-literals rule, and `` is the right quoting system given the characters left that can be easily typed and that don't ding readability.
Yes, I love them and hope that assignment via ${=x} makes it into ES.next, because that’ll enable us to do all kinds of matching.
We have <| but it is a bit contentious. No one has topped it, though, and a keyword instead seems to lose on both restricted-production and no-better-word-than-<| grounds.
I like that one, it’s very visual; I find it more descriptive than the keyword "proto".
Some find -> and => cryptic, but it's hard to say the only alternative is to stick to eight-letter 'function'. ('lambda' is not reserved and can't be used without breaking compatibility; and it's six letters.)
Some find block-lambdas with their Ruby- (and to a lesser extend Smalltalk-) inspired {||...} bracketing cryptic.
-
Pro block-lambdas: A new construct that can be used in places where dynamic |this| (that normal functions are always going to have) would be a burden.
-
Pro arrows: little semantic change. With the shorthand for methods in object literals, there is the question whether dynamic |this| is ever needed. But if we need both dynamic and lexical |this|, then the arrows are nice in that they look similar, but are still different.
-
Pro ƒ: short, syntactically very similar to current semantics and syntax. And as easy to type on a German Mac keyboard as curly braces and square brackets. But I respect the reasoning against it and am in awe that you still have the patience to discuss this kind of issue.
There are other options, but they all face genreric "too much line noise!" objections.
Programming language syntax is in the same category as politics and religion: There are few simple compromises.
This is me being oblivious to many of the gory details, but if only my taste mattered, then I would do the following:
==== Instead of (example in the proposal) ... ====
var obj = theProtoObj <| {.seal, ~konst:= f(), handler: defaultHandler, ~get super set name(v) {throw Error("some message")}, source() {throw Error("another message")}, toString() {return "d "+super.toString()} };
==== ... write the following ====
var obj = theProtoObj <| {.seal, @const konst: f(),
handler: defaultHandler,
get name() {
return super.name;
},
set name(v) {
throw Error("some message");
},
source() {throw new Error("another message")},
toString() {return "d "+super.toString()},
];
==== Rationale ====
-
Does enumerability ever matter?
-
Passing the getter through to the super-class seems like a rare use case. Doing so manually could be optimized by a compiler and while it is a tiny bit verbose, it clearly expresses what is going on. The proposed shorthand is hard to parse for me. Alternative:
get name() super, set name(v) { throw Error("some message"); },
On Jun 20, 2011, at 12:40 PM, Axel Rauschmayer wrote:
Quasi-literals rule, and `` is the right quoting system given the characters left that can be easily typed and that don't ding readability.
Yes, I love them and hope that assignment via ${=x} makes it into ES.next, because that’ll enable us to do all kinds of matching.
Me too.
We have <| but it is a bit contentious. No one has topped it, though, and a keyword instead seems to lose on both restricted-production and no-better-word-than-<| grounds.
I like that one, it’s very visual; I find it more descriptive than the keyword "proto".
Great.
Some find -> and => cryptic, but it's hard to say the only alternative is to stick to eight-letter 'function'. ('lambda' is not reserved and can't be used without breaking compatibility; and it's six letters.)
Some find block-lambdas with their Ruby- (and to a lesser extend Smalltalk-) inspired {||...} bracketing cryptic.
- Pro block-lambdas: A new construct that can be used in places where dynamic |this| (that normal functions are always going to have) would be a burden.
And for other purposes, such as block-like "bodies" of Array forEach, etc. methods.
- Pro arrows: little semantic change.
No semantic change, I claim. What differs apart from syntax?
There's a dependency on completion reform, but that is a separate semantic change (already in Harmony).
With the shorthand for methods in object literals, there is the question whether dynamic |this| is ever needed.
This does not make sense.
Object literals used for prototypes have methods but those methods must use dynamic |this| because the calls use individual instances as their reference bases, not the prototype.
But if we need both dynamic and lexical |this|, then the arrows are nice in that they look similar, but are still different.
Dynamic |this| is an essential part of the prototypal pattern.
- Pro ƒ: short, syntactically very similar to current semantics and syntax.
The florin works no better than Greek lower-case lambda. Both are already legal ES3-5.1 Identifiers and cannot be retasked as keywords, especially not with the name of the function in a function expression optional.
var obj = theProtoObj <| {.seal, @const konst: f(),
Too verbose, and requiring it to be on its own line compounds the problem by taking too much vertical space. Plus, we have no decorator proposal yet. Plus on top, decorators are for metadata that may be erased, or that at least must be optional. Non-writability in ES5 and up is not optional or erasable.
- Does enumerability ever matter?
It sure does. Consider how PrototypeJS extends standard prototypes. See
- Pro block-lambdas: A new construct that can be used in places where dynamic |this| (that normal functions are always going to have) would be a burden.
And for other purposes, such as block-like "bodies" of Array forEach, etc. methods.
Right, you want lexical |this| in these cases and the dynamic |this| (of regular functions) gets in the way. I consider that a benefit of block-lambdas (in addition to them having a compact syntax and their support for break etc.).
- Pro arrows: little semantic change.
No semantic change, I claim. What differs apart from syntax?
Correct. I meant “less semantic change” (that with block lambdas), but “no semantic change” puts it better.
With the shorthand for methods in object literals, there is the question whether dynamic |this| is ever needed.
This does not make sense.
Object literals used for prototypes have methods but those methods must use dynamic |this| because the calls use individual instances as their reference bases, not the prototype.
I meant: One can already write methods (functions with dynamic |this|) in a very concise manner, thanks for Allen’s object literal extensions. Then you have to ask: Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>.
- Pro ƒ: short, syntactically very similar to current semantics and syntax.
The florin works no better than Greek lower-case lambda. Both are already legal ES3-5.1 Identifiers and cannot be retasked as keywords, especially not with the name of the function in a function expression optional.
Ah, damn, I knew it was a very convincing argument. ;-) There is still the faint hope that this isn’t actually used in practice, but still.
On Jun 20, 2011, at 4:31 PM, Axel Rauschmayer wrote:
With the shorthand for methods in object literals, there is the question whether dynamic |this| is ever needed.
This does not make sense.
Object literals used for prototypes have methods but those methods must use dynamic |this| because the calls use individual instances as their reference bases, not the prototype.
I meant: One can already write methods (functions with dynamic |this|) in a very concise manner, thanks for Allen’s object literal extensions. Then you have to ask: Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>.
We do not propose to cripple the shorter syntax. The dynamic-this use-cases for functions are at least as common as "var self=this;... function(){... self...}" use-cases for lexical this, or roughly about the same (in my experience -- anyone have data?).
I meant: One can already write methods (functions with dynamic |this|) in a very concise manner, thanks for Allen’s object literal extensions. Then you have to ask: Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>.
We do not propose to cripple the shorter syntax. The dynamic-this use-cases for functions are at least as common as "var self=this;... function(){... self...}" use-cases for lexical this, or roughly about the same (in my experience -- anyone have data?).
Are functions that depend on dynamic |this| ever not methods? Wouldn’t you always want to use an object literal for methods, especially if some features (such as |super|) depend on it?
Isn’t it then a case of { foo: (x) -> { ... } }
versus { foo(x) { ... } }
On the other hand, if the ability to omit returns can only be got via arrow->functions then I can see why you would want to keep them for methods. But even implicit returns seem to matter most in non-method settings (e.g. if a function is the argument of a function).
Maybe I just like the distinction introduced by block lambdas too much:
- dynamic this --> existing functions and methods
- lexical this --> new, more compact construct, mainly used as the argument of functions and methods.
This distinction works well as a rule of thumb and keeps things easy to explain.
On Jun 20, 2011, at 4:56 PM, Axel Rauschmayer wrote:
I meant: One can already write methods (functions with dynamic |this|) in a very concise manner, thanks for Allen’s object literal extensions. Then you have to ask: Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>.
We do not propose to cripple the shorter syntax. The dynamic-this use-cases for functions are at least as common as "var self=this;... function(){... self...}" use-cases for lexical this, or roughly about the same (in my experience -- anyone have data?).
Are functions that depend on dynamic |this| ever not methods?
Sure. The main use-case is constructors (and you can make a function do double-duty, as a constructor or a function called without 'new').
Also, some times, people write functions not used as methods but called via .call or .apply. It happens.
On the other side of the fence, it's not uncommon to have "methods" that want lexical or no |this|. In the closure pattern, you often see code like so:
function Car(make, model, key) { function validate(key) {...} function cancelAlarm() {...} return { start: function (key) { if (validate(key)) { cancelAlarm(); ... } }, lock: function ..., unlock: function ..., // etc. }; }
The methods of the object literal do not use |this|, but if they did, they might prefer to use => and avoid the hazard of an accidental |this| reference within one of their bodies being re-bindable.
Wouldn’t you always want to use an object literal for methods, especially if some features (such as |super|) depend on it?
Probably. But so what?
We're not making mandatory syntax either way with function, so why should we with arrow?
Isn’t it then a case of { foo: (x) -> { ... } }
You mean => here, I think.
versus { foo(x) { ... } }
Arrows are not in yet. The method syntax looks like it is the most agreed-to among the harmony:concise_object_literal_extensions at this point.
BTW, if Arrows make it then, as with binding forms such as const and let, the property assignment shorthand will be
{ foo(x) => ... } // or =>, and with ... an expression or block
Maybe I just like the distinction introduced by block lambdas too much:
- dynamic this --> existing functions and methods
- lexical this --> new, more compact construct, mainly used as the argument of functions and methods.
Block-lambdas are not arrows. Arrows are just syntax and try to shorten function usage in general (including the .bind or var self=this; idiom). Block-lambdas must preserve Tennent's Correspondence Principle, so they have no choice but to treat |this| lexically.
This distinction works well as a rule of thumb and keeps things easy to explain.
It's not that simple: existing functions can and do use various binding hacks to make |this| or a substitute "lexical". Anyway, functions have |this| parameters, whether created by old function or new arrow syntax.
On Jun 20, 2011, at 5:27 PM, Brendan Eich wrote:
Isn’t it then a case of { foo: (x) -> { ... } }
You mean => here, I think.
versus { foo(x) { ... } }
Er, you mean ->. Sorry,
Plus on top, decorators are for metadata that may be erased, or that at least must be optional. Non-writability in ES5 and up is not optional or erasable.
IIRC then Python decorators are functions that are applied to the property value (not entirely unlike quasis). This could be adapted to pass in |this| plus property name plus value for properties and be used for all kinds of things.
Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>. Are functions that depend on dynamic |this| ever not methods?
Sure. The main use-case is constructors (and you can make a function do double-duty, as a constructor or a function called without 'new').
With classes, constructors will become methods, right?
Also, some times, people write functions not used as methods but called via .call or .apply. It happens.
Wouldn’t it be better to have lexical |this| in these cases, so that foo.call(null, ...) does not affect |this|? But I see what you mean, you cannot use normal .bind(), because of the way it handles the arguments that the bound function receives. Maybe use something like the following to implement =>, then?
Function.prototype.bindOnlyThis = function (myThis) { var that = this; return function() { return that.apply(myThis, arguments); }; }
Wouldn’t you always want to use an object literal for methods, especially if some features (such as |super|) depend on it?
Probably. But so what?
We're not making mandatory syntax either way with function, so why should we with arrow?
Old-style functions would be rarely used and there would be a clear separation of concerns:
- Want a method? Use an object literal.
- Want a function that is not a method (i.e., lexical this)? Use an arrow function with =>
This would make things easier to understand. When I explain this aspect of JavaScript to others, they are often stumped, but I have never encountered anyone who was confused by Python: class MyClass: def mymethod(self): return "hello world" def myfunction(): return "hello world"
So this is probably my real point: can we make things as un-confusing as in Python?
Maybe I just like the distinction introduced by block lambdas too much:
- dynamic this --> existing functions and methods
- lexical this --> new, more compact construct, mainly used as the argument of functions and methods.
Block-lambdas are not arrows. Arrows are just syntax and try to shorten function usage in general (including the .bind or var self=this; idiom). Block-lambdas must preserve Tennent's Correspondence Principle, so they have no choice but to treat |this| lexically.
I know. But block-lambdas enforce a separation of concerns (because they have no choice, really) that I would like short-syntax functions (arrows or not) to enforce, as well.
This distinction works well as a rule of thumb and keeps things easy to explain.
It's not that simple: existing functions can and do use various binding hacks to make |this| or a substitute "lexical". Anyway, functions have |this| parameters, whether created by old function or new arrow syntax.
Right. That could be a problem, the abstraction I have in mind might become leaky at some point.
On Jun 21, 2011, at 2:18 AM, Axel Rauschmayer wrote:
Do we really need the dynamic this arrow ->, or can we make do with just the lexical this arrow =>. Are functions that depend on dynamic |this| ever not methods?
Sure. The main use-case is constructors (and you can make a function do double-duty, as a constructor or a function called without 'new').
With classes, constructors will become methods, right?
Not in the sense we were discussing, where you could call new o.C or else o.C().
Yes, C.prototype.constructor === C, but people don't write "x = new C; y = new x.constructor" much. You can, that is possible in JS today without classes.
Again, classes are sugar for the prototypal pattern. They don't add anything different or magic about how the constructor and the prototype reference each other.
Also, some times, people write functions not used as methods but called via .call or .apply. It happens.
Wouldn’t it be better to have lexical |this| in these cases, so that foo.call(null, ...) does not affect |this|?
No, the .call and .apply cases I cited, which intentionally pass varying (dynamic) objects as the first argument, need that first argument to bind to the |this| parameter.
Wouldn’t you always want to use an object literal for methods, especially if some features (such as |super|) depend on it?
Probably. But so what?
We're not making mandatory syntax either way with function, so why should we with arrow?
Old-style functions would be rarely used and there would be a clear separation of concerns:
- Want a method? Use an object literal.
That's too restrictive. JS allows the Google Closure style of assigning methods via C.prototype.m1 = function.., etc.
- Want a function that is not a method (i.e., lexical this)? Use an arrow function with =>
I think you are trying to restrict JS users in ways they won't like. Anyway, we can't make an incompatible change to functions. Arrows as proposed are just syntax for functions, including with |this| bound lexically.
If we make arrows restrictive in ways that functions (with either dynamic or lexical this-binding) are not restricted, we're essentially telling some JS programmers that they're "doing something wrong" or "using forms that are hard to understand for beginners".
Sorry, there's no evidence for such claims, and without such evidence, it's not a good idea for TC39 to put itself in such a "restrictionist" position.
(Contrast this with 'with', dynamic eval var injection, and other things banned by strict mode where lexical scope, capability leaks, and optimizability were all destroyed by the banned forms.)
This would make things easier to understand. When I explain this aspect of JavaScript to others, they are often stumped, but I have never encountered anyone who was confused by Python: class MyClass: def mymethod(self): return "hello world" def myfunction(): return "hello world"
So this is probably my real point: can we make things as un-confusing as in Python?
Python has its confusing parts too.
Anyway, if you are talking about making classes less confusing, that's a fine goal for classes.
But shorter function syntax needs to be shorter without requiring only "lexical this", given all the "dynamic this" use-cases including methods assigned as in Google Closure. Functions are used in several ways in JS and the overlong syntax (both 'function' and 'return') are a problem for several of the use-cases.
Method syntax as specified for Harmony inside object literals does have dynamc this-binding. There's no dispute about that.
Maybe I just like the distinction introduced by block lambdas too much:
- dynamic this --> existing functions and methods
- lexical this --> new, more compact construct, mainly used as the argument of functions and methods.
Block-lambdas are not arrows. Arrows are just syntax and try to shorten function usage in general (including the .bind or var self=this; idiom). Block-lambdas must preserve Tennent's Correspondence Principle, so they have no choice but to treat |this| lexically.
I know. But block-lambdas enforce a separation of concerns (because they have no choice, really) that I would like short-syntax functions (arrows or not) to enforce, as well.
That's nice for the use-cases that want lexical-this. For dynamic-this, it's a usability burden without justification.
Explaining things to beginners still will involve explaining 'function' (long-form) syntax for the foreseeable future, so you don't gain anything by crippling arrow syntax.
But once beginners learn more, they will hate having to write out the long form for all the dynamic this cases that can't be written using method-in-initialiser syntax.
This distinction works well as a rule of thumb and keeps things easy to explain.
It's not that simple: existing functions can and do use various binding hacks to make |this| or a substitute "lexical". Anyway, functions have |this| parameters, whether created by old function or new arrow syntax.
Right. That could be a problem, the abstraction I have in mind might become leaky at some point.
We want orthogonal primitives with good syntax. This not only reduces such "leaks" but increases serendipity. Users will discover things we did not foresee, which otherwise would be restricted in lumpy or hard-to-use ways, or just impossible.
This would make things easier to understand. When I explain this aspect of JavaScript to others, they are often stumped, but I have never encountered anyone who was confused by Python: class MyClass: def mymethod(self): return "hello world" def myfunction(): return "hello world"
So this is probably my real point: can we make things as un-confusing as in Python?
Python has its confusing parts too.
Yes, I only meant when it comes to functions versus methods.
Explaining things to beginners still will involve explaining 'function' (long-form) syntax for the foreseeable future, so you don't gain anything by crippling arrow syntax.
But once beginners learn more, they will hate having to write out the long form for all the dynamic this cases that can't be written using method-in-initialiser syntax.
Agreed. If a simplification could be done naturally, that would be great. But as that seems impossible, forcing things does not make sense.
Would it make sense to include a shorthand for calling Object.defineProperty() to object literals?
Possible benefits:
=== Example ===
var Multiplier = { FACTOR :: { value: 3, writable: false }, multiply: function (x) { return x * this.FACTOR; } }