I recently posted a feature request for AS3 asking for property initialization for instance construction. If you want details, check out bug #ASL-69.
In one of the comments, I referenced an existing way to quickly set properties on a new typed object, and thought it might be worth sharing. It’s super simple, but might prove useful.
Simply put the following code into a “setProps.as” file in your class path:
package { public function setProps(o:Object, props:Object):* { for (var n:String in props) { o[n] = props[n]; } return o; } } |
Now, from anywhere in your code, you can quickly set multiple properties on an object. This can be handy when creating new instances. For example:
addChild( setProps( new Sprite(), {x:200, y:200, alpha:0.5, name:"bob"} ) ); |
This obviously isn’t type-safe, and it won’t provide compile time errors if you get a property name wrong. For small projects with short timelines, or just playing around it can make it easier to hack things together, but I don’t recommend it for larger or more formal projects.
The goal of my feature request was to enable similar ease of use, but with type safety, compile time errors, and full IDE support. Feel free to vote for it here.
This would be nice, but it seems like you can get most of the way there using a “with” block. Here’s your example from the feature request:
var foo = new Sprite() {x:200, y:300, alpha:0.3, visible:false}
And here it is using a “with” block:
var foo = new Sprite() with(foo){x=200; y=300; alpha=0.3; visible=false;}
You do have to type “with (foo)”, but other than that it’s just changing : to = and , to ;
This gives you type safety, compile time errors, and full IDE support already, so I think it’s a pretty good alternative to go along with your setProps function for now.
Jackson – actually, “with” does not provide type safety, compile time errors, or IDE support (at least not in the manner I am looking for with ASL-69).
Heh your title was little bit misleading for me.
Knowing your affection to optimizing stuff (I guess any good programmer should be like that :D) I tought it will be about some optimized way to do that 🙂 But it is actually a development speed thing then run time speed.
Grant – I hadn’t noticed before that “with” doesn’t do strict checking at compile time. This is quite unfortunate! Still, “with” could be used as another type-unsafe alternative to ASL-69 like setProps.
In this way –
with ((this.addChild(new Sprite())).graphics)beginFill(0xFF0000), drawRect(0,0,100,100);
looks like –
setProps( (this.addChild(new Sprite())).graphics, {beginFill(0xFF0000), drawRect(0,0,100,100)} ) );
I’m not sure …
with (addChild(new Sprite()))
{
x = 200;
y = 300;
alpha = 0.3;
visible = false;
}
This is exaclty the same, only shorter.
Mark – the “with” keyword is notoriously slow, to the point that I usually just avoid it. It also makes it harder to do a variable assignment:
var child = addChild( setProps(new Sprite(), {x:200, … }) );
vs.
var child;
with (child = addChild(new Sprite())) { … }
But yes, it’s definitely a usable approach, as long as you are aware of the above considerations.
sorry for advertisement, but Realaxy guys say their new editor has language extension doing just that:
var foo = Sprite{
x:200;
y:300;
alpha:0.3;
visible:false
}
Their overall approach is to _make_ language extension instead of having to _request_ it from adobe and hope they’d listen… It’s not clear if their editor users are in the same position.
Toss in a check there!
if(o.hasOwnProperty(n)
{
o[n] = props[n];
}else{
trace(“YOU HAVE NO “+n+” property for that object!”)
}
Nice idea to have this syntax from as3, i have already include this kind of stuff in mylib components framework (http://mylib.samystudio.net, http://mylib.samystudio.net/?page_id=306), never thought this could be include natively.
Should be great if you could give feeback/advices from mylib components since i know you’re close from adobe’s 😉
Nice suggestion, Grant. In C#, this is called “Initializer”, and it definitely saves a lot of typing and it is easier to read, too.
hey i thought nobody uses flash anymore 🙂
Hi Grat,
I use somethink like this in years for now. I have 3 custom classes, tha extends Sprite, Bitmap and TextField. In each class i Includde:
public function setAttrs(a:Object):* {
this.attrs = new Hash(a);
return this;
}
public function set attrs(attributes:Object):* { // setter function for sipmple setting params like hash
if (attributes) {
for (var n:String in attributes) {
this[n] = attributes[n];
}
}
return attributes;
}
// some display shortcuts
public function get aspect():Aspect { return new Aspect(this.width, this.height); }
public function set aspect(value:Aspect):void { if(!this.rect.equals(value.toRect())){this.x = value.x; this.y = value.y, this.width = value.width; this.height = value.height}; }
//Get the dimensions of this object (width and height) as an Array ([width,height])
public function get dims():Array { return [this.width, this.height]; }
public function set dims(value:*):void {
if(value is Array){
this.width = value[0];
this.height = value[1];
}else{
this.width = this.height = value;
}
}
//Get the position of this object (x and y) as an Array ([x,y])
public function get pos():Array { return [this.x, this.y]; }
public function set pos(value:Array):void { this.x = value[0]; this.y = value[1]; }
//Get the position and dimenstions of this object (width, height, x and y) as a Rectangle object
public function get rect():Rectangle { return new Rectangle(this.x, this.y, this.width, this.height); }
public function set rect(value:Rectangle):void { if(!this.rect.equals(value)){this.x = value.x; this.y = value.y, this.width = value.width; this.height = value.height} }
// verical position functions
public function sendFront():void {
this.parent.setChildIndex(this,this.parent.numChildren – 1);
}
public function sendBelow(child:DisplayObject):void {
this.parent.setChildIndex(this, this.parent.getChildIndex(child))
}
public function sendAbove(child:DisplayObject):void {
this.parent.setChildIndex(this, this.parent.getChildIndex(child));
this.parent.swapChildren(this, child);
}
public function sendBack():void {
this.parent.setChildIndex(this,0);
}
This functions are very usefull. for example i have
var a:bySprite = new bySprite({width:100,height:200})
a.attes = {x:100, color:”lime”}
Feel free to use 🙂
But this only works with Standar Object.
Many classes are “not enumerable” and “setProps” simple fails!.
It’s better to use “describeType(source)” and collect getters and variables!
I think, your approach is ugly. These are my reasons:
First of all, addChild() must have DisplayObject as its argument. But your method accepts Object, and returns an Object to add it to the display list? 🙂
Secondly, setProps() seems like a setter method. Therefore, it is confusing to see the reason why it returns any object type to add to the display list. It will cause many problems.
Finally, the type of the first argument of setProps() is “Object”. It is not good. It should be at least “DisplayObject” type.
Sincerely,
luchyx – it works fine to set values on any object, but you are correct that the properties object must be enumerable. Perhaps you are missing the point of the method, which is to quickly assign arbitrary property values, not to clone properties from one typed object to another.
ozgur – If you would care to read my whole post, you will note that I specific mention strict-typing as an issue with this approach, and recommended against using it in formal projects for this reason.
The setProps method requires loose typing in order to be flexible, so that it can be used with any object type. I used a DisplayObject only for illustration.
The lack of strict typing (and related compile-time errors) in this approach is one of the reasons I proposed the ASL-69 feature request which you subsequently commented against.
@ozgur uksal: Why should the first argument be a displayobject? True, the example Grant gave an ‘addChild’ is used. but not every object has to be added to the displaylist
for instance:
var order:PizzaOrder = setProps(new PizzaOrder(), {cheese: ‘chedar’ });
BTW, reminds me of the “good” old AS2 days:
mc = this.attachMovieClip(“linkageName”, “stageAsset”, this.getNextHighestDepth(), {_x: 100, _y: 200 });
:p
It would be a good shortcut Grant. I voted for it.