I read a question on stackoverflow (couldn't find it now) about how variables in a method can be only accessed in that method, but the code still works with the answer being an analogy of a hotel room. In AS3, I believe everything that's not primitive gets passed as a reference. So, the following code would be the same as that question and isn't guaranteed to work?
public class Testy {
private var foo:Array;
public function Testy(input:Array) {
// Allow the whole class to access it
foo = input;
}
public function traceFoo(){
trace(foo);
}
}
Now, foo would be a reference to the input argument in the class' constructor. Is this safe code/good practice? Thanks!
Yes this is safe/good code practice as long as you don't want to manipulate the original Array. If you want to manipulate the original array, allow public access to the array by making it a public var or using a public getter/setter.
What you've described is a property, and is inline with encapsulation of object oriented programming.
This would expose a getter and setter:
package
{
import flash.display.Sprite;
public class Testy extends Sprite
{
private var _foo:Array;
public function get foo():Array
{
return _foo;
}
public function set foo(value:Array):void
{
_foo = value;
}
public function Testy()
{
super();
}
}
}
Also it's better to return _foo.concat() in getter not to break encapsulation.
Related
Hi my problem is i have to be able to reference certain fields inside my Customer object.]
I am studying AS3 at the moment and being taught custom classes, but we are taught to use the toString method of returning a value i guess you could call it, what i need is to be able to call one field to identify the object i.e. name field from the object in the array, here's my code
package valueObjects
{
public class Person
{
//instance variables
protected var name:String;
protected var address:String;
protected var phoneNo:String;
public function Person(n:String,a:String,p:String)
{
name=n;
address=a;
phoneNo=p;
}
public function toString():String
{
//returns string
return name+":"+address+":"+phoneNo;
}
}
}
some reason it will not put that whole block of code together like THIS IS
So now how do i define it not toString but in object form ??
I think what you are trying to do is access the name, address and phoneNo vars from a different class?
If so, you have to declare them as public vars instead of private vars.
public var name:String; //now this can be accessed from other classes: thisClassInstance.name
If you want to have them read-only from other classes, you have to use a getter method:
protected var name_:String; //local var name for full access;
public function get name():String {
return name_; //this can be access by doing thisClassInstance.name
}
That title probably made no sense, so I'll try to explain.
Let's say I create a class in AS3, any class with some basic vars, and those vars are set through that classes constructor
so..
var class = new basicClass(var1, var2);
Now let's say I want to create a new class which inherits the basicClass's vars/methods etc, so new class has something like
public class betterClass extends basicClass
and maybe that also has some vars that are set via it's constructor.
Now what I'm confused about is, how do you set the parent classes (basicClass) vars or do anything through it's constructor by creating betterClass?
If basicClass has a constructor which expects values, then how do you set that up, by doing...
var class2 = new betterClass(var3, var4)
because var3 and var4 are for the constructor of betterClass, I don't see how an instance of basicClass is setup.
I know this is pretty basic stuff, it's just I've never needed to use inheritance before.
So you have got BasicClass, its constructor may look like this:
public function BasicClass(var1:*, var2:*)
{
//do some stuff with var1 and var2
}
//you can extend some metods too
public function niceFunction():void
{
trace('Oh! Hello!');
}
Now you can create BetterClass:
public function BetterClass(var3:*, var4:*)
{
super(var3, var4);
//this calls constructor of BasicClass
}
override public function niceFunction():void
{
super.niceFunction();
trace('Nice to meet you.');
//This will trace: Oh! Hello! Nice to meet you.
}
You can call the parent class's constructor from your extending class using the 'super' keyword'
public betterClass(){
super(constuctorParam1,constructorParam2);// this calls the constructor of the class this class extended
}
Here is more detailed info
http://ntt.cc/2009/07/26/beginning-actionscript-3-super-this-setter-getter.html
Sometimes, you have different signatures
package {
public class A {
protected var _a:String, _b:String;
public function A(a:String, b:String) {
_a = a;
_b = b;
}
}
}
package {
public class B extends A {
private var _c:Number;
public function B(c:Number) {
super('', '');
_c = c;
}
}
}
You have to be aware of the different arguments and their meaning. Also, provide useful defaults if possible.
Just some additional input.
I'm making a game in action script 3. In it, I have an actor class from which player and enemy classes will be derived. I'm doing this so that unless I need to provide specific AI or fancy behavior (such as for bosses), I can just make a new clip in the library for each enemy without making an actionscript file.
However, I've run into a problem.
Whenever I try to pass arguments to the construction of an enemy (make it spawn with more health), I get error 1136 (Incorrect number of arguments.)
This is because the constructor created automatically at runtime doesn't have the same arguments as it's parent class. Is there any way to get around this without making a class file where I copy and paste the parent constructor function for each of my hundreds of enemies?
Edit
actually rereading your question I think you may be looking for super();
Example
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Class that extends Actor:
public class Boss extends Actor{
public function Boss(){
super(200); //passes 200 to Actor;
}
}
If you're trying to pass data into a classes constructor you need to make sure it's accepting arguments.
public class Actor{
private var myHelth:uint;
public function Actor(helth:uint = 100){
myHelth = helth; //this will be set to 100 if nothing it passed in or the value passed
}
}
Then to use
var a:Actor = new Actor(200); //setting health to 200
var b:Actor = new Actor(); //using the default of 100
Make sure your symbols in Flash Pro have appropriate AS linkage, then use pass constructor arguments in super statements:
Actor - base class
package
{
public class Actor
{
public function Actor(name:String, role:String)
{
}
}
}
Player - inherits from Actor defining its own constructor parameters:
package
{
public final class Player extends Actor
{
public function Player(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}
Enemy - inherits from Actor defining its own constructor parameters:
package
{
public final class Enemy extends Actor
{
public function Enemy(... params:Array)
{
// pass desired inherited constructor parameters
super("name", "role");
}
}
}
Does anyone know of a framework, preferably some way to have the Flex compiler run an extension or perhaps just a build step that we could generate strongly typed proxy classes of our application's data models.
There are 2 main things we want to do with the proxy's:
At runtime we want to lazily parse and instantiate the instance as accessed (similiar to how Java's Hibernate has Lazy proxy objects)
In an editor application we want to implement setter calls so we can track which objects have been modified
The Proxy is really necessary in this situation beyond things like programatically setting up ChangeWatcther's because we need to track Array adds/remove and possibly track "reference" objects so that when a "reference key" is changed we know to save those objects that are referencing it by key
In the first case we want the proxy to basically abstract when that object is loaded from serialized data, but still pass around references of it with the same public properties and data access pattern if it were the real object.
Basically the proxy would instantiate the object the first time a method is called on it.
I know we could use some AS3 byte-code libraries like as3-commons-bytecode.
Or possibly repurposing the GraniteDS Code Generation.
I'd prefer to generate code because it is a deterministic thing and it'd be nice if we could have a way to debug it at runtime easier.
Does anyone know if I could do something like MXMLC does when it generates AS3 code from MXML files.
Also is there anyway to control "when" in the compilation pipeline I can generate code, because we have a lot of data objects using public fields instead of getter/setters, but that are [Bindable] and so if I could generate the proxy based on the generated getter/setter methods that would work.
Here's an example application data object and proxy classes:
[Bindable]
public class PersonDTO implements Serializable {
private var _name:String;
private var _age:Number
public function get age():Number {
return _age;
}
public function set age(a:Number):void {
_age = a;
}
public function get name():String {
return _name;
}
public function set name(n:String):void {
_name = n;
}
public void readObject(data:*) {
//...
}
}
// GENERATED CLASS BASED ON PersonDTO
public class LazyProxy_PersonDTO extends PersonDTO {
private var _instance:PersonDTO = null;
private var _instanceData:*;
private function getInstance():void {
if (_instance == null) {
_instance = new PersonDTO();
_instance.readObject(_instanceData);
}
}
override public function get age():Number {
//Ensure object is instantiated
return getInstance().age;
}
override public function get name():String {
//Ensure object is instantiated
return getInstance().name;
}
}
// GENERATED CLASS BASED ON PersonDTO
public class LogChangeProxy_PersonDTO extends PersonDTO {
//This will be set in the application
public var instance:PersonDTO;
//set by application
public var dirtyWatcher:DirtyWatcherManager;
override public function set age(a:Number):void {
dirtyWatcher.markAsDirty(instance);
instance.age = a;
}
}
Digging a little deeper into AS3-Commons byte code library it looks like they support generating proxy classes and interceptors.
http://www.as3commons.org/as3-commons-bytecode/proxy.html
public class DirtyUpdateInterceptor implements IInterceptor {
public function DirtyUpdateInterceptor() {
super();
}
public function intercept(invocation:IMethodInvocation):void {
if (invocation.kind === MethodInvocationKind.SETTER) {
if (invocation.arguments[0] != invocation.instance[invocation.targetMember]) {
invocation.instance.isDirty = true;
}
}
}
}
What I am trying to do is kind of odd, but I am wondering if anyone can come up with a clever way to do what I want to do. Basically, I want to re-define a named function at runtime. I can do this with anonymous functions, but I can't figure out a way to do it for named functions. I want to do this so that I can implement a "spy" functionality on an object for a testing framework (a port of Jasmine to Flex).
Take, for instance, this class:
public class TestClass
{
public var anonymous:Function = function():void {
trace("original anonymous");
};
public function named():void {
trace("original named");
}
}
I can easily re-define the anonymous function because it is just a variable. Javascript uses this idiom a lot.
var testClass:TestClass = new TestClass();
testClass.anonymous = function():void { trace("overridden anonymous"); }
BUT, when I do the same thing for named functions, you get a compile-time error:
// Does not compile
testClass.named = function():void { trace("overridden named"); }
I tried to make it a bit more "squishy" but this leads to a runtime failure "Cannot assign to a method named on TestClass".
// Compiles with runtime failure
testClass["named"] = function():void { trace("overridden named"); }
Can anyone more clever than I come up with a way to hack this? Can the bytecode be hijacked? Something?
I want to modify an object, not a
class
But object doesn't contain functions, only non-static variables. I tried to use prototype property and replace method there, but original method still gets called instead of injected one.
About "hack" bytecode, do you mean "hack" already loaded SWF in runtime? I think it's not possible. I'm sure, though, you can parse SWF with something like as3swf, find method in bytecode, replace it and save result in new SWF.
I had an idea bout making a function "cache" . This might work with what you need.
Let's say you have a class "Car" with a method you need to redefine at runtime:
public class Car extends Sprite
{
private var functionCache:Function;
public function Car()
{
super();
}
public function flexibleFunction(functionBody:*=null):void{
if(functionBody is Function){
functionBody.call();
functionCache=functionBody;
} else {
functionCache(functionBody);
}
}
}
Usage:
public class Main extends Sprite
{
private var car:Car;
public function Main()
{
car = new Car();
car.flexibleFunction(function(){trace("redefine test #1")});
car.flexibleFunction();
car.flexibleFunction(function(doParametersWork:String="let's see"){trace("redefine test #2: " + doParametersWork);});
car.flexibleFunction("yes they do");
car.flexibleFunction();
}
}
an easy way to accomplish what you want is to simply pass a new function to the original function and execute it from there:
package
{
//Imports
import flash.display.Sprite;
//Class
public class RedefineFunction extends Sprite
{
//Constructor
public function RedefineFunction()
{
originalFunction();
originalFunction(redefinedFunction);
}
//Original Function
public function originalFunction(redefinition:Function = null):void
{
if (redefinition != null)
redefinition();
else
trace("Original Function Definition");
}
//Redefined Function
private function redefinedFunction():void
{
trace("Redefined Function Definition")
}
}
}
traces:
Original Function Definition
Redefined Function Definition