Closed Bug 306920 Opened 19 years ago Closed 19 years ago

Using a setter breaks ECMA assignment semantics

Categories

(Core :: JavaScript Engine, defect)

x86
Windows XP
defect
Not set
normal

Tracking

()

RESOLVED WORKSFORME

People

(Reporter: ldavismead, Unassigned)

References

()

Details

(Keywords: testcase)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20050901 SeaMonkey/1.1a

Aunty ECMA sez (262 3/e):
(quote)
11.13.1 Simple Assignment ( = )
The production AssignmentExpression : LeftHandSideExpression =
AssignmentExpression is evaluated
as follows:
1. Evaluate LeftHandSideExpression.
2. Evaluate AssignmentExpression.
3. Call GetValue(Result(2)).
4. Call PutValue(Result(1), Result(3)).
5. Return Result(3)
(end quote)

When using a setter, the result of the assignment expression (the one we're
evaluating, not the one on the RHS) is evaluated as the return value of the
setter rather than the value computed for the RHS.

Reproducible: Always

Steps to Reproduce:
1. Click on the javascript:url testcase.
Actual Results:  
Alerts "foo" (the value returned from the setter).

Expected Results:  
Should alert "bar" (the value of the RHS).

Also appears in Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5)
Gecko/20041107 Firefox/1.0

I really just wanted to point this out if you didn't know about it, since it's a
little surprising if you're not expecting it.  Most setters don't return values
(that I know of), so those accustomed to assignment expressions evaluating to
the RHS might be surprised when they evaluate to undefined if the LHS has a
setter they don't know about (it evaluates to the return value of the setter,
which would be undefined for the unsuspecting setter implementor).  I know
getters and setters are super-secret undocumented stuff, so I've no problems if
this gets WONTFIXed.  I will point out that the current behaviour allows a
useful "neat trick," which might very well explain why it works the way it does,
you sneaky developer-persons, you.

function stringWrapper(s)
{
	this.__defineGetter__("s", function()
	{
		return s;
	});

	this.__defineSetter__("s", function(value)
	{
		var oldVal = s;
		s = value;
		return oldVal;
	});
}

var foo = new stringWrapper("foo");
var bar = new stringWrapper("bar");

/* Swap foo's and bar's strings in a very sneaky way.  Note
   that the getters aren't actually called anywhere in this
   statement.  */
foo.s = bar.s = foo.s;

foo = new stringWrapper("foo");
bar = new stringWrapper("bar");
var baz = new stringWrapper("baz");
var quux = new stringWrapper("quux");

/* "Rotate" the strings.  Again no getters are called.  After
   this line executes:
   foo.s == "bar"
   bar.s == "baz"
   baz.s == "quux"
   quux.s == "foo"  */
foo = bar = baz = quux = foo;
Well, ****.  The last sneaky example should have been

foo.s = bar.s = baz.s = quux.s = foo.s

obviously.
Keywords: testcase
This works as intended, and it does not "break" ECMA so much as extend it
(allowed for new syntax by ECMA-262 Edition 3 Section 16).

/be
Status: UNCONFIRMED → RESOLVED
Closed: 19 years ago
Resolution: --- → WORKSFORME
You need to log in before you can comment on or make changes to this bug.