Are classes methods created individually for instances? - actionscript-3

I want to know whether in ActionScript 3 there's a way to share a same function (method) between the instances of a class definition, only referencing the same function everytime... i.e., this example should log true, but logged false (note: I'd want this to reduce duplicating functions).
class A {
function f() {}
}
trace(
(new A).f === (new A).f
)
An ActionScript 3 language specification appears to say that a prototype attribute exists, but not implemented. I've understood that individual classes have a prototype object. I've specially found a prototype property (probably inherited from Class/Object) and wonder if classes use meta functions in order to be constructed (since their type is "object"... when I test with typeof: trace(typeof A, typeof Class, typeof Object)).
My last try:
class A {}
A.prototype.f = function() {}
trace(
(new A).f === (new A).f
)
It says that f doesn't exist. I could define this class as a function instead (in order to move methods to the prototype object):
function A() {}
A.prototype.f = function() {}
, but in this way I can't control access of instance members.

AS3 uses Bound methods to ensure that inside your functions, this always points to original instance object by default.
Imagine that you pass a function f of an instance a to some other object b. When then object b calls function f, the this name still points to a inside scope of the function - this reference has to be store somewhere.
Well, you could assign function to static property of your class:
package adnss.projects.evTest
{
public class A {
private var x:Number = 5;
private var _y:Number = 0;
public function A(){}
static public const f = function (p:Number):Number {
this._y = p;
return this.x*p;
}
public function get y():Number { return _y; }
}
}
And then have access to private properties of the instance of A in that static function by explicitly using this:
var instance:A = new A();
trace("return:", A.f.call(instance, 3)); //return: 15
trace("instace:", instance.y); //instance: 3
But that is kind of tricky for possible benefits (if any).
And about prototypes. You basically don't use them in AS3. Is't there like a souvenir :) - read this for more info

Related

AS3 Dynamically create an instance of an object

I have a class which contains the following method to place an object on the stage.
public function createBox()
{
var box:Ball1 = new Ball1();
addChild(box);
box.addEventListener(Event.ENTER_FRAME, boxF);
}
What I would like to do is to is pass an object name to the method, and load that object instead, thus allowing me to use the same method for different objects.
A non-working example:
public function createBox( obj )
{
var box:obj = new obj();
addChild(box);
box.addEventListener(Event.ENTER_FRAME, boxF);
}
Is this possible?
Thanks
A more agile version of the existing answer is to use getDefinitionByName(), which allows you to construct a class based on an input string.
Using this function, you can rewrite the method to something like this:
public function produce(className:String):*
{
var type:Class = getDefinitionByName(className) as Class;
return new type();
}
Advanced:
To make this stricter and more maintainable (make it so only certain factories can create certain classes), you can use an interface to build a relationship between a given factory and the classes it can produce. A small example of this follows below.
Say a factory, EnemyFactory, creates objects that you would consider to be enemies in a game. We don't want to be able to create things like pickups, particles and other non-enemy type objects. We can create an interface IEnemyProduct which is implemented by classes that the EnemyFactory is allowed to create. The interface could be as simple as:
public interface IEnemyProduct{}
Which would be implemented by any enemy classes. The EnemyFactory's produce() function can then be modified to a more readable version, like this:
public function produce(enemyClassName:String):IEnemyProduct
{
var type:Class = getDefinitionByName(enemyClassName) as Class;
return new type() as IEnemyProduct;
}
In this case, produce() will return null if the produced class does not implement IEnemyProduct. The goal here is to make it obvious which factories are responsible for which objects, which is a big advantage once the project becomes larger. The use of an interface rather than a base class also means you can implement multiple interfaces and have the class produced by multiple factories.
You could maybe use a simple factory, or something similar:
public class Factory
{
public static function produce(obj:String)
{
if (obj == "obj1")
{
return new obj1();
} else if (obj == "obj2") {
return new obj2();
}
}
}

CircularList in ActionScript 3

I have been working on an AS3 project for some while and I think that I've hit a wall. My project requires a series of elements to be arranged in a Circular List, so I copied myself in a Circular List I had done before in C#.
Problem is, that one was heavily dependant on the usage of Generics. Now I don't have those.
Here are the codes. The T variable type represents the generics that I wish existed.
Node.as:
package
{
public class Node
{
var nodeContent:T;
var nextNode:Node;
function Node(nodeElement:T)
{
this.nodeContent = nodeElement;
}
}
}
CircularList.as:
package
{
public class CircularList
{
var head:Node;
var tail:Node;
var listLength:int;
function CircularList()
{
this.head = null;
this.tail = null;
this.listLength = 0;
}
function Add(addition:T)
{
adding:Node = new Node(addition);
if(this.head == null)
{
this.head = adding;
this.tail = adding;
head.nextNode = tail;
tail.nextNode = head;
}
else
{
tail.nextNode = adding;
tail = adding;
tail.nextNode = head;
}
listLength++;
}
function Find(requested:T):Node
{
var finder:Node = null;
var searching = head;
var i:int;
while(i <= listLength)
{
if(searching.nodeContent == requested)
{
finder = searching;
}
searching = searchig.nextNode;
i++;
}
return finder;
}
}
}
Is there a way to make this thing work without the generics?
EDIT: The real problem with this is that I want the NodeContent in the Node class to be an object. I want to make a list of people sitting on a circular table, basically, but I would like to have a code that I can reuse, rather than something specifically made for this problem
From the comments it seems like your best option here would be to use an interface.
Instead of using a type have all classes T implement an interface like INode. In this interface you can define all the functionality that your type T requires and implement it as needed in each of your implementing classes. This way you can change your function signatures to take type INode instead of Class or * and have a common set of methods that these functions can act upon.
function Add(addition:INode){
//add logic on INode
}
function Find(requested:INode):Node{
//find logic on INode
}
edit: a bit of info about interfaces,
http://active.tutsplus.com/tutorials/actionscript/as3-101-oop-introduction-to-interfaces/
say we have two Classes, A, B and each of these classes have a similar method, doTrace, that needs to be implemented differently. We can define an interface, implement it in both of these classes and pass that type into any method looking to call doTrace
Start with the interface called ITraceable,
public interface ITraceable{
function doTrace():void //all methods defined in interfaces are seen as public
}
Now our two Classes, A and B
public class A implements ITraceable { //implementing our interface, when we do this we need to define all methods in ITraceable
public function doTrace():void{
trace("I am A");
}
}
Do a similar thing for B
public class B implements ITraceable {
public function doTrace():void{
trace("I am B");
}
}
Now in some outside class we want to use this
public function letsTrace():void{
doTheTrace(new A()) //I am A
doTheTrace(new B()) //I am B
}
public function doTheTrace(object:ITraceable):void { //now we can pass both A and B into this function
object.doTrace(); //since ITraceable requires all objects that implement it have this method we can guarantee it will be here
}
Hope this helps you through your application

actionscript 3.0 error 1069 "this" cannot find declared variable outside of function

"This" is incapable of finding the appropriate variable "array1" despite it clearly being declared within the function. But if I declare the variables outside of the function it works. How can I have the variables inside the function but keep it working?
package
{
public class main extends MovieClip
{
//If I declared the variables here it would work.
public function main():void
{
var array1:Array = [1,2];
var array2:Array = [3,4];
trace(this["array"+1][1]); //returns reference error 1069
}
}
}
Am I stuck with declaring the variables outside of the function?
And no, multidimensional arrays won't work for what I need it for. Though it looks like it would solve everything within the code snippet provided huh?
My intentions is to pass arrays through a class to be used and change which array bunch I use. If I used multidimensional arrays, it would be inefficient due to the amount of copying that would occur.
For this[] to access properties, those properties must belong to this. In your sample, the properties belong to the function in which they were defined and are inaccessible outside of that scope.
So firstly; yes, for your code to work you will of course need to define properties in the class level scope.
But more importantly I'd look closely at what you're trying to do and determine whether it's a good approach - my bet is that it's not. It seems like you may want to consider an isolated class that deals with all the data you want to store.
Your error is because you mis-scoped the variables.
The "this" keyword means you are trying to target a variable on the specific instance of the class.
You have scoped the variables locally to the function.
You need to move them to the class declaration area for "this" to work.
package
{
public class main extends MovieClip
{
public var array1:Array = [1,2];
public var array2:Array = [3,4];
public function main():void
{
trace(this["array"+1][1]); //returns reference error 1069
}
}
}
// now if you meant to scope them locally to the function then you can not use "this"
// you have to assign them to an object or an array
package
{
public class main extends MovieClip
{
public function main():void
{
var obj:Object = {}
obj['array1'] = new Array( [1,2] )
obj['array2'] = new Array( [3,4] )
trace(obj["array"+1][1]);
}
}
}
This is untested code but it should put you on the right track.
Depending on what you are trying to accomplish exactly, you can also consider passing an array as an argument to a function, something like:
function main():void
{
var array1:Array = [1,2];
var array2:Array = [3,4];
doSomethingWithArray(array2);
}
main();
function doSomethingWithArray(arr:Array):void
{
trace(arr[1]); //Traces the value of array2[1], which = 4
}
Also consider having a var currentArray:Array that you can set as any array you'd like and refer to it as needed, if applicable.
public class main extends MovieClip
{
...
public var currentArray:Array;
function main():void
{
var array1:Array = [1,2];
currentArray = array1;
doSomethingithCurrentArray();
var array2:Array = [3,4];
currentArray = array2;
doSomethingithCurrentArray();
currentArray = null;
}
public function doSomethingithCurrentArray():void {
if(currentArray != null){
trace(currentArray);
}
}
}

AS3 reflection. How to find out if a method is overridden?

Is it possible to use AS3 reflection to find out if a method was overridden?
I need a method like:
protected function isOverriden(methodName:string) : bool
{
//magic here!
//...
return awesomeLocalVariable;
}
So, I pass in the method name as a string and the isOverridden method yields true only if and only if the object has a method of that name and it is overridden from its original implementation.
Any idea on how to code the magic there?
Thanks.
Edit: As requested, the context of the problem:
I'm building a framework for creating AS3 games. I want to provide "components" for my game objects, each component provides functionality to the game object it is applied. Components are based on events (onClick, onUpdate, onShapeCollision, etc) I need this code in the Component class, so I can register only the events that the actual Component-derived class implements (overrides).
Example component:
public class CTrace extends ScriptComponent
{
public override function onClick(event:MouseEvent = null):void
{
trace(Owner.Id);
}
}
The framework should register the onClick method as the event handler for the MouseEvent.CLICK event because it overrides the default implementation.
Why do I need the default implementation? Because I want the classes to override the supported methods so there will be a compile time error if the user tries to use an unsupported event.
Does that makes sense?
Here is a try. The function is static and it may be used to check any class or object regardless of the class in which it is implemented. If you give it the type, it will use it, if you give it an instance, it will get the type by itself. The inner logic is just to check the given type description for the function we are looking for, if such exists and is declared by the class, it will check if the method also exists in the parent. And if both exists, enjoy, it means it is overridden.
/**
* Returns true only if the method name given is declared by
* the source class, and any parent class.
*/
static public function isOverridden(source:*, methodName:String):Boolean {
var parentTypeName:String = getQualifiedSuperclassName(source);
if (parentTypeName == null) {
return false;
}//if
var typeName:String = getQualifiedClassName(source);
var typeDesc:XML = describeType(getDefinitionByName(typeName));
var methodList:XMLList = typeDesc.factory.method.(#name == methodName);
if (methodList.length() > 0) {
//Method exists
var methodData:XML = methodList[0];
if (methodData.#declaredBy == typeName) {
//Method is declared in self
var parentTypeDesc:XML = describeType(getDefinitionByName(parentTypeName));
var parentMethodList:XMLList = parentTypeDesc.factory.method.(#name == methodName);
return parentMethodList.length() > 0;
}//if
}//if
return false;
}//isOverridden
And just in case it is needed, the imports required for it to work:
import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.utils.getQualifiedSuperclassName;
And to use it:
trace(isOverridden(ChildrenClass, "overriddenMethod")); //true
trace(isOverridden(ChildrenClass, "onlyChildMethod")); //false
trace(isOverridden(ChildrenClass, "onlyParentMethod")); //false
If you are asking inside the same object you can
overriden = (this[stringNameOfMethod] instanceOf Function && super[stringNameOfMethod] instanceOf Function);
If not, try using describeType. Check if there's a method with the name and check the "declaredBy" attribute. Voila!
http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/utils/package.html#describeType()
Sorry, I'm in the middle of a migration from CS3 to Flash builder so for now I cannot ensure my ideas work correctly. But I will be back.

How do I make an Action Script 3 class, used in two SWF files, resolve to the same class when one SWF dynamically loads the other?

Background
I am developing a highly modular application in pure Action Script 3 (we are using Flex 4 SDK to automate our builds, but all our code must be able to compile directly in Flash CS4 Professional).
We have a "framework.swc" file which contains interface definitions which are shared between all our modules, we have a "mainmodule.swf" that loads our other modules, and then we have various .swf files for our other modules. We are using the Loader class, in conjuction with ApplicationDomain::getDefinition() for loading classes dynamically [we use "new LoaderContext(false,ApplicationDomain.currentDomain)"].
Problem
All our modules implement the "AbstractModule" interface, which is defined in "framework.swc". When I instantiate a dynamically loaded module, however, (module is AbstractModule) returns false. More importantly, if I call module.someMethod(someobject), where someobject implements an interface defined in "framework.swc" and where the module's method expects an object of the same interface defined in "framework.swc", I get a runtime error "TypeError: Error #1034: Type Coercion failed: cannot convert _ to _."
It seems that "mainmodule.swf" and "loadedmodule.swf" (the module I have been loading for testing), are, internally, using separate definitions for the shared interfaces in "framework.swc"
Question
How can I make "mainmodule.swf" and "loadedmodule.swf" resolve their common interfaces to a shared definition, so that class casting and class comparison succeed correctly?
Ok. This isn't the prettiest solution, but it will work. Basically, for every interface "AbstractX" (replace "X" with something else), you need to create two wrapper classes: "ImportX" and "ExportX". The goal of ExportX is to successfully widen AbstractX to type Object, by wrapping an AbstractX, providing all the same methods as type AbstractX, but to use only builtin/predefined data types or data types which are part of flash in their signatures. The goal of ImportX is to narrow a dynamically loaded object with the same characteristics as type AbstractX (but which cannot be cast to type AbstractX and which is not recognized as type AbstractX) but is of type Object to the AbstractX interface. Both ExportX and ImportX use ImportY, ImportZ, etc.; however, ExportX uses ImportY, ImportZ, etc. to wrap parameters, which it delegates to an object of type AbstractX, while ImportX uses them to wrap return values, which come about from delegating to an object of type Object. To make this a little more understandable, I present the following examples:
public interface AbstractX
{
// The export/import functions are mandatory
// for all such interfaces. They allow
// for the wrappers to be correctly manipulated.
function export() : Object;
function original() : Object;
// The interface functions vary from
// interface to interface. They can
// be called something much more appropriate.
function interfaceFunction1(param : AbstractY) : AbstractZ;
function interfaceFunction2(param : AbstractA) : AbstractB;
}
// A class of type Import_ always implements Abstract_
public class ImportX implements AbstractX
{
// The constructor for an Import_ Object
// is always of type Object.
public function ImportX(obj : Object) : void {
_loadedobj = obj;
_exportobj = obj.export();
}
// Every Import_ class must implement a similar "wrap" function:
public static function wrap(obj : Object) : AbstractX {
var result : AbstractX = null;
if ( obj != null ){
if ( obj is AbstractX ){ // Don't wrap if convertible, directly.
result = obj as AbstractX;
}else if ( obj.original() is AbstractX ){ // Don't double wrap
result = obj.original() as AbstractX;
}else{
// Needs to be wrapped.
result = new ImportX(obj);
}
}
return result;
}
public function export() : Object {
return _exportobj;
}
public function original() : Object {
return _loadedobj;
}
// For the interface functions, we delegate to _exportobj
// and we wrap the return values, but not the parameters.
public function interfaceFunction1(param : AbstractY) : AbstractZ {
return AbstractZ.wrap(_exportobj.interfaceFunction1(param));
}
public function interfaceFunction2(param : AbstractA) : AbstractB {
return AbstractB.wrap(_exportobj.interfaceFunction2(param));
}
private var _loadedobj : Object;
private var _exportobj : Object;
}
// Although an Export_ object provides SIMILAR methods to type Abstract_,
// the signatures need to be changed so that only builtin/predefined types
// appear. Thus Export_ NEVER implements Abstract_.
public class ExportX
{
// The constructor to Export_ always takes an object of type Abstract_
public function ExportX(obj : AbstractX) : void {
_obj = obj;
}
public function original() : Object {
return _obj;
}
public function export() : Object {
return this;
}
// For the interface functions, we delegate to _obj
// and we wrap the parameters, not the return values.
// Also note the change in signature.
public function interfaceFunction1(param : Object) : Object {
return _obj.interfaceFunction1(AbstractY.wrap(param));
}
public function interfaceFunction2(param : Object) : Object {
return _obj.interfaceFunction2(AbstractA.wrap(param));
}
private var _obj : AbstractX = null;
}
// The definition of class X can occur in and be loaded by any module.
public class X implements AbstractX
{
public function X( /* ... */ ) : void {
//...
}
public function export() : Object {
if ( ! _export ){
_export = new ExportX(this);
}
return _export;
}
public function original() : Object {
return this;
}
public function interfaceFunction1(param : AbstractY) : AbstractZ {
// ...
}
public function interfaceFunction2(param : AbstractA) : AbstractB {
// ...
}
private var _export : Object = null;
}
// Ok. So here is how you use this...
var classx : Class = dynamicallyLoadClassFromModule("X","module.swf");
var untypedx : Object = new classx();
var typedx : AbstractX = ImportX.wrap(untypedx);
// Use typedx ...
you should try -compiler.external-library-path as documented here ... that way, you can build one swc having dependancies on an interface, that is not in it, but comes from another, thus avoiding collisions ... don't know how to do that in CS4 though ...
greetz
back2dos
You may want to use a Runtime Shared Library (RSL). An RSL allows you to do dynamic linking. However, I don't know if CS4 can build those. Maybe you could reconsider the "must be able to compile directly in Flash CS4" requirement, or look into compiling using the Flex SDK through macros/scripts in the CS4 IDE.
If that's absolutely not an option, another approach would be to have a looser coupling between modules, and rely on more of an implied common external interface for the module SWFs instead of code-level integration.
I'm not 100% sure if its what you need, but Gaia Framework implements a global API, shared by many swfs to interact with each other. You could check it out and maybe get some ideas. Right now I'm confronted with quite a similar situation as yours, so I'm checking alternatives... this post will be very useful, thanks!