Assignment to method invocation result
On Thu, May 15, 2014 at 7:27 AM, Jussi Kalliokoski < jussi.kalliokoski at gmail.com> wrote:
Throughout my history with JS (and pretty much every programming language I've used) I've always found one thing really awkward: reassigning a variable to the result of its method.
Say you have code like this:
var foo = function (options) { var string = something();
if ( options.stripWhiteSpace ) { string = string.trim(); }
// do something else here... };
The same thing applies to pretty much all methods that return a modified version of the same type of the variable, e.g. replace, filter, map, concat, etc., you name it.
As a comparison let's say we had Number#add() and no operators for the add method:
var bar = function (firstNumber, secondNumber) { var thirdNumber = 5; if ( firstNumber > 0 ) { secondNumber = secondNumber.add(thirdNumber); } firstNumber = firstNumber.add(secondNumber); };
whereas with the operators we have the convenience of combining the operator with the assignment to avoid typing the variable name twice:
var bar = function (firstNumber, secondNumber) { var thirdNumber = 5; if ( firstNumber > 0 ) { secondNumber += thirdNumber; } firstNumber += secondNumber; };
I don't really know what would be a good solution for this problem, hence I wanted to share this here if we can figure out a nicer way to do these kinds of things. The best I can think of is some syntax like this:
var foo = function (options) { var string = something();
if ( options.stripWhiteSpace ) { string = .trim(); }
// do something else here... };
so basically the operator would a combination of assignment followed by property access dot, then the method name and invocation. This could also allow plain property access so you could for example say
foo = .first
or something. The reason I don't like this syntax is that it might be conflicting with other some ideas thrown around to replacewith
, e.g.:using (foo) { .remove(x); var x = .size; }
This particular syntax would also require static (a lookahead) and semantic (based on the lookahead results) disambiguation to account for DecimalLiteral:
var n = .2;
If the "." was on the other side?
AccessorAssignmentOperator : .= IdentifierName
var string = " a ";
string .= trim(); // would throw if no trim
method existed for string
string; // "a";
Where ".=" means assign the result of "Property Accessors Runtime Semantics Evaluation" with lval and rval in appropriate positions (TBH, I'm sure I missed something in there)
and what about
obj []= 'propertyName'
as well? --scott
On Thu, May 15, 2014 at 2:27 PM, C. Scott Ananian <ecmascript at cscott.net>wrote:
and what about
obj []= 'propertyName'
as well? --scott
I imagined .= would do both, but I don't think my suggestion should be taken seriously. In fact, your example illustrates a major flaw (that exists in either proposal/suggestion), that I don't immediately know how I would answer:
var o = { foo: "bar" }; o .= foo;
Is o
now a string with the value "bar"?? I think that would cause more
problems than its worth.
On Thu, May 15, 2014 at 8:47 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
I imagined .= would do both, but I don't think my suggestion should be taken seriously. In fact, your example illustrates a major flaw (that exists in either proposal/suggestion), that I don't immediately know how I would answer:
var o = { foo: "bar" }; o .= foo;
Is
o
now a string with the value "bar"?? I think that would cause more problems than its worth.
Yes, that's exactly what it would do. This sort of pattern is even reasonably common when doing tree-walking, for example: you see a lot of "node = node.left;" or whatnot.
Le 15 mai 2014 à 20:17, Rick Waldron <waldron.rick at gmail.com> a écrit :
If the "." was on the other side?
AccessorAssignmentOperator : .= IdentifierName
var string = " a "; string .= trim(); // would throw if no
trim
method existed forstring
string; // "a";
Where ".=" means assign the result of "Property Accessors Runtime Semantics Evaluation" with lval and rval in appropriate positions (TBH, I'm sure I missed something in there)
There is an interesting question of precedence/associativity. Normally, for a binary operator @, the two lines are more or less the equivalent:
a @= foo(bar).baz() + quax
a = a @ (foo(bar).baz() + quax)
But when you write, say
str .= replace(/_/g, ' ').trim() + ' foo'
you probably don't mean
str = str.(replace(/_/g, ' ').trim() + ' foo')
but rather:
str = (str.replace)(/_/g, ' ').trim() + ' foo'
On Thu, May 15, 2014 at 9:17 PM, Rick Waldron <waldron.rick at gmail.com>wrote:
This particular syntax would also require static (a lookahead) and semantic (based on the lookahead results) disambiguation to account for DecimalLiteral:
var n = .2;
True. However, it's a good thing valid identifiers can't start with a number, otherwise even lookahead couldn't save it. :P
If the "." was on the other side?
AccessorAssignmentOperator : .= IdentifierName
I deliberately avoided that because I've seen it proposed for Object.extend() syntactic sugar a couple of times:
foo .= { bar: 1 };
( proposed as doing roughly the same as _.extend(foo, { bar: 1 });
)
But I have no personal preference either way.
On Fri, May 16, 2014 at 1:55 AM, Tab Atkins Jr. <jackalmage at gmail.com>wrote:
On Thu, May 15, 2014 at 8:47 PM, Rick Waldron <waldron.rick at gmail.com> wrote:
I imagined .= would do both, but I don't think my suggestion should be taken seriously. In fact, your example illustrates a major flaw (that exists in either proposal/suggestion), that I don't immediately know how I would answer:
var o = { foo: "bar" }; o .= foo;
Is
o
now a string with the value "bar"?? I think that would cause more problems than its worth.Yes, that's exactly what it would do. This sort of pattern is even reasonably common when doing tree-walking, for example: you see a lot of "node = node.left;" or whatnot.
In your example, is it safe to assume that node.left
is a node? I'm
familiar with this precedent on a daily basis ;) It was the "object becomes
a string" behaviour that I was objecting to.
On 16 May 2014 15:08, "Rick Waldron" <waldron.rick at gmail.com> wrote:
On Fri, May 16, 2014 at 1:55 AM, Tab Atkins Jr. <jackalmage at gmail.com>
wrote:
On Thu, May 15, 2014 at 8:47 PM, Rick Waldron <waldron.rick at gmail.com>
wrote:
I imagined .= would do both, but I don't think my suggestion should be
taken
seriously. In fact, your example illustrates a major flaw (that exists
in
either proposal/suggestion), that I don't immediately know how I would answer:
var o = { foo: "bar" }; o .= foo;
Is
o
now a string with the value "bar"?? I think that would cause
more
problems than its worth.
Yes, that's exactly what it would do. This sort of pattern is even reasonably common when doing tree-walking, for example: you see a lot of "node = node.left;" or whatnot.
In your example, is it safe to assume that
node.left
is a node? I'm
familiar with this precedent on a daily basis ;) It was the "object becomes a string" behaviour that I was objecting to.
I'm not a fan of objects becoming strings either, but that problem exists with methods as well:
var foo = ["bar", "baz"]; foo .= join();
However, I don't think it's a problem introduced by this proposal, nor addressible by it, but rather by something like guards:
var foo : Array = ["bar", "baz"]; foo .= join(); // Error
This doesn't seem like such a big win to devote an entirely new syntax to. Now we have to document it, put it in all the tooling, all the IDEs, teach it, somehow make it accessible to Google search, etc.
Just write "string = string.trim();", or better yet, "let trimmedString = string.trim();"
Throughout my history with JS (and pretty much every programming language I've used) I've always found one thing really awkward: reassigning a variable to the result of its method.
Say you have code like this:
var foo = function (options) { var string = something();
if ( options.stripWhiteSpace ) { string = string.trim(); }
// do something else here... };
The same thing applies to pretty much all methods that return a modified version of the same type of the variable, e.g. replace, filter, map, concat, etc., you name it.
As a comparison let's say we had Number#add() and no operators for the add method:
var bar = function (firstNumber, secondNumber) { var thirdNumber = 5; if ( firstNumber > 0 ) { secondNumber = secondNumber.add(thirdNumber); } firstNumber = firstNumber.add(secondNumber); };
whereas with the operators we have the convenience of combining the operator with the assignment to avoid typing the variable name twice:
var bar = function (firstNumber, secondNumber) { var thirdNumber = 5; if ( firstNumber > 0 ) { secondNumber += thirdNumber; } firstNumber += secondNumber; };
I don't really know what would be a good solution for this problem, hence I wanted to share this here if we can figure out a nicer way to do these kinds of things. The best I can think of is some syntax like this:
var foo = function (options) { var string = something();
if ( options.stripWhiteSpace ) { string = .trim(); }
// do something else here... };
so basically the operator would a combination of assignment followed by property access dot, then the method name and invocation. This could also allow plain property access so you could for example say
foo = .first
or something. The reason I don't like this syntax is that it might be conflicting with other some ideas thrown around to replacewith
, e.g.:using (foo) { .remove(x); var x = .size; }