forked from: プリミティブな値の扱い getter、setterと a = c, b = c OR a = (b = c)

by 9re forked from プリミティブな値の扱い getter、setterと a = c, b = c OR a = (b = c) (diff: 21)
getter が呼ばれない…変数の参照なしにプリミティブな値の代入が行われてる?
->
=演算子は右結合だから、a = (b = c)と評価されて、
aに代入されるのはcの値ではなく、b = cという式を評価した値なので、getterは呼ばれない。

From http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
11.13.1 Simple Assignment ( = ) 
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 
1. Let lref be the result of evaluating LeftHandSideExpression. 
2. Let rref be the result of evaluating AssignmentExpression. 
3. Let rval be GetValue(rref). 
4. Throw a SyntaxError exception if the following conditions are all true: 
• Type(lref) is Reference is true
• IsStrictReference(lref) is true
• Type(GetBase(lref)) is Enviroment Record 
• GetReferencedName(lref) is either "eval" or "arguments"
5. Call PutValue(lref, rval). 
6. Return rval.
♥0 | Line 97 | Modified 2010-11-02 16:05:22 | MIT License
play

ActionScript3 source code

/**
 * Copyright 9re ( http://wonderfl.net/user/9re )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/1DJr
 */

// forked from alumican_net's プリミティブな値の扱い getter、setterと a = c, b = c  OR a = (b = c)
// forked from madflash's プリミティブな値の扱い
// getter が呼ばれない…変数の参照なしにプリミティブな値の代入が行われてる?

// ->
// =演算子は右結合だから、a = (b = c)と評価されて、
// aに代入されるのはcの値ではなく、b = cという式を評価した値なので、getterは呼ばれない。

/**
From http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf
11.13.1 Simple Assignment ( = ) 
The production AssignmentExpression : LeftHandSideExpression = AssignmentExpression is evaluated as follows: 
1. Let lref be the result of evaluating LeftHandSideExpression. 
2. Let rref be the result of evaluating AssignmentExpression. 
3. Let rval be GetValue(rref). 
4. Throw a SyntaxError exception if the following conditions are all true: 
• Type(lref) is Reference is true
• IsStrictReference(lref) is true
• Type(GetBase(lref)) is Enviroment Record 
• GetReferencedName(lref) is either "eval" or "arguments"
5. Call PutValue(lref, rval). 
6. Return rval. 
*/

package {
    import flash.display.Sprite;
    public class Substitution extends Sprite {
        private var trace:Tracer = new Tracer();
        private var _a:uint = 0;
        private var _b:uint = 0;       
        private var _c:uint = 1;    
        
        private function set a(a_:uint):void
        {
            trace.dev("call by set a: "+a_);
            _a = a_;
        }
        private function get a():uint
        {
            trace.dev("call by get a: "+_a);
            return _a;
        }
        private function set b(b_:uint):void
        {
            trace.dev("call by set b: "+b_);
            _b = b_;
        }
        private function get b():uint
        {
            trace.dev("call by get b: "+_b);
            return _b;
        }
        
        private function get c():uint
        {
            trace.dev("call by get c: "+_c);
            return _c;
        }
        
        public function Substitution()
        {
            trace.property( { x:20, y:20 } );
            trace.isDevelop = true; 
            addChild( trace.create );
            
            //代入
            trace.push("代入のみ");
            a = b = c;
            trace.push("参照(getterが呼ばれる)");
            a = b;
            
            trace.show();
        }
    }
}

import flash.system.IME;
import flash.display.*;
import flash.text.*;

class Tracer extends Sprite
{
    public var format:TextFormat;
    public var txt:TextField;
    private static const NEWLINE:String = "\n";
    private var _log:String = "";
    private var _isDev:Boolean = false;
    
    public function get create() :TextField { return txt }; //getter
    public function get log() :String { return _log };
    public function get isDevelop() :Boolean { return _isDev };
    public function set isDevelop(bool:Boolean) :void { _isDev = bool };
    
    public function Tracer(format_:TextFormat = null)
    {
        format = new TextFormat();
        txt = new TextField();
        //format
        var ref:* = (format_) ? format_ : {color:0x000000, size:12, font:'MS Gothic'};
        PropertyScan( format, ref );
        //prop
        var prop:Object = { x:0, y:0, autoSize:TextFieldAutoSize.LEFT };
        PropertyScan( txt, prop );
        //format done
        txt.defaultTextFormat = format;
    }
    // function has 4 params. implement dynamic param nomber.
    // x, y, width, height or Object/Array
    public function property(...args):void
    {
        const properties:Array = new Array('x','y','width','height');
        var isArray:Boolean = (args[0] is Array) ? true : false;
        var params:* = isArray ? args[0] : args;
        var Q:uint = params.length; //Queue
        
        if (isArray || (Q<=4 && !(params is Object)) ) for (var i:uint=0; i<Q; i++) txt[properties[i]] = params[i];
        else PropertyScan(txt, args[0]);
    }
    public function push(...args) :void { _log += Roller(args) + NEWLINE };
    public function show() :void { txt.htmlText = _log };
    public function dev(...args) :void
    {
        if (_isDev) _log += ("<b><font color='#ff0000'>" + Roller(args) + "</font></b>" + NEWLINE) ;
    }
    /* static functions, logic designed by madflash */
    private static function Roller(...args) :String
    {
        var str:String = "";
        if ( args.length <= 1 ) str += String(args);
        else for each(var e:Object in args){str += (String(e) + " ")};
        
        return str;
    }
    private static function PropertyScan(target:*, ref:*) :void
    {
        if (target is Object && ref is Object)
            for(var key:String in ref) target[key] = ref[key];   
    }
}

Forked