Run code before class instanciation in ActionScript 3 - actionscript-3

I need to run code in a class declaration before its instanciation. This would be especially useful to automatically register classes in a factory. See:
// Main.as
public class Main extends Sprite
{
public function Main() : void
{
var o : Object = Factory.make(42);
}
}
// Factory.as
public class Factory
{
private static var _factory : Array = new Array();
public static function registerClass(id : uint, c : Class) : void
{
_factory[id] = function () : Object { return new c(); };
}
public static function make(id : uint) : Object
{
return _factory[id]();
}
}
// Foo.as
public class Foo
{
// Run this code before instanciating Foo!
Factory.registerClass(CLASS_ID, Foo);
public static const CLASS_ID : uint = 42;
}
AFAIK, the JIT machine for the ActionScript language won't let me do that since no reference to Foo is made in the Main method. The Foo class being generated, I can't (and don't want to) register the classes in Main: I'd like to register all the exported classes in a specific package (or library). Ideally, this would be done through package introspection, which doesn't exist in ActionScript 3.
Do you know any fix (or other solution) to my design issue?

I'm not 100% sure sure if this is what you're after, but have you tried using a Static Initializer?
public class Foo
{
// Static Initializer
{
Factory.registerClass(CLASS_ID, Foo);
}
public static const CLASS_ID : uint = 42;
}
http://life.neophi.com/danielr/2006/12/static_initializers_in_as3.html

You can use compiler options to include class byte code in the resulting SWF or SWC. But you have to compile with MXMLC (or COMPC for SWCs).

Related

Why do I get a 0 width for a class instantiated by static variable

Here is a Monitor class. I am trying to get it's width, through it's static property. So that, to get width, I can write : Monitor.width, Monitor.height
However, when I instantiate, it through a static variable, the instantiation is successful, but still returns a 0 value width. Is their any alternative way ( other than instantiating it inside the get width and get height method itself ) ?
package {
import flash.display.*;
public class Monitor extends MovieClip {
private static var staticInstance: Monitor = new Monitor();
public function Monitor() {
}
static public function get width(): Number {
// staticInstance: Monitor = new Monitor() <<< this will work
return staticInstance.width;
}
static public function get height(): Number {
// staticInstance: Monitor = new Monitor() <<< this will work
return staticInstance.height;
}
}
}
When trying :
trace(Monitor.width) // output is 0
You shouldn't do this with a display list type. Static code gets executed when your class gets initialized by virtual machine (i.e. in internal Monitor$cinit() method), and it will not create visuals for you. Try placing trace(this.width); in Monitor constructor and see that it returns zero with your approach.
If you are absolutely sure, that you need a singletone here (which is not the case most of the time), use the "classic" idiom:
package
{
import flash.display.MovieClip;
public class Monitor extends MovieClip
{
private static var instance : Monitor;
public static function getInstance()
{
if (instance == null) {
instance = new Monitor();
}
return instance;
}
public static function get width()
{
return getInstance().width;
}
public function Monitor()
{
trace("Monitor constructor: "+this.width);
}
}
}
When you do:
trace("Monitor.width = "+Monitor.width);
The output should be:
Monitor constructor: some_number
Monitor.width = some_number
That is correct since static variables are computed before anything else when your program starts so a graphic object can't really have any size at this point.
The correct way to deal with this is to delay the instantiation with a classic getInstance() for example:
private static var staticInstance: Monitor;
No instantiation to start with then:
static private function get instance():Monitor
{
if(!staticInstance)
{
staticInstance = new Monitor();
}
return staticInstance;
}
Now use this getter in all your calls:
static public function get height(): Number
{
return instance.height;
}

PythonQt how to override virtual function

I am trying to add Python scripting capability to my Qt application. So far, I have been able to write wrappers for many classes. However, one class has a virtual 'init()' function which can be overridden by a derived class if necessary.
// C++ class
class MyClass : public QObject
{
Q_OBJECT
public:
MyClass()
{
init(); // perform user initialization
}
virtual void init() {}
};
The MyClass constructor calls the virtual function 'init()'. It is intended that when MyClass is sub-classed that the init function can be overridden if necessary to provide user initialization.
I wish to use 'MyClass' in PythonQt so I have written a wrapper class:
class MyClass_Wrapper : public QObject
{
Q_OBJECT
public Q_SLOTS:
// add a constructor
MyClass* new_MyClass() {return new MyClass(); }
void init(MyClass* mc) { mc->init(); }
};
The class 'MyClass' is now registered with PythonQt:
PythonQt::self()->registerCPPClass("MyClass",NULL,"myModule", PythonQtCreateObject<MyClass_Wrapper>);
Now, I create a Python script to use 'MyClass':
import myModule
Class TestClass(MyClass) :
def init(self):
# init() is called exactly once at the beginning to do
# any necessary configuration.
print "Inside init(self)"
.
.
.
return
The problem is that the print statement (and the following code) is never executing. The init() function is not being overridden by the PythonQt code.

AS3 - how to extend this function

This is first class with "gordz()" function
public class Model extends Object implements IModel
{
public static function gordz() : void
{
newobject = gallas.pop();
}
}
Now i try to override the function but i still want that old code is executed... How can i extend this function correctly?
public class LOL extends Model
{
override public static function gordz() : void
{
... //New code + execute old code
}
}
Neither super
You cannot use the super statement in a static method.
nor override
You cannot use the override attribute on any of the following:
[...]
Static methods
can be used in a static method.
Whatever you are trying to do should be accomplished in a different way.

registering open generic decorators for typed implementations in castle windsor

While trying to coerce Windsor into wrapping an implementation with a random number of decorators, i've stumbled upon the following:
i have 3 decorators and an implementation all using the same interface.
if you run this code, windsor resolves icommandhandler<stringcommand> as implementation, which, as far as i can tell, is expected behaviour, because the typed implementation can not be registered with the open typed decorators.
However, if you uncomment the line container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());, all three decorators will be used to resolve implementation, which is the desired result (sort of : ).
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer();
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator1<>)));
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator2<>)));
container.Register(Component.For(typeof(ICommandHandler<>)).ImplementedBy(typeof(Decorator3<>)));
//uncomment the line below and watch the magic happen
//container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<Decorator1<stringCommand>>());
container.Register(Component.For<ICommandHandler<stringCommand>>().ImplementedBy<implementation>());
var stringCommandHandler = container.Resolve<ICommandHandler<stringCommand>>();
var command = new stringCommand();
stringCommandHandler.Handle(command);
Console.WriteLine(command.s);
Console.ReadKey();
}
}
public interface ICommandHandler<T>
{
void Handle(T t);
}
public class stringCommand
{
public string s { get; set; }
}
public abstract class Decorator<T> : ICommandHandler<T>
{
public abstract void Handle(T t);
};
public class Decorator1<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator1(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator1;";
_handler.Handle(t);
}
}
public class Decorator2<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator2(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator2;";
_handler.Handle(t);
}
}
public class Decorator3<T> : Decorator<T>
where T : stringCommand
{
private ICommandHandler<T> _handler;
public Decorator3(ICommandHandler<T> handler)
{
_handler = handler;
}
public override void Handle(T t)
{
t.s += "Decorator3;";
_handler.Handle(t);
}
}
public class implementation : ICommandHandler<stringCommand>
{
public void Handle(stringCommand t)
{
t.s += "implementation;";
}
}
Why exactly is this happening, is this a feature of windsor that i am not aware of? Is there perhaps a different way to achieve the same effect? (without resorting to reflection)
When windsor tries to resolve a component it will first try to resolve the more specific interface. So when you register Component.For it will prefer to resolve this over an open generic type.
If the same interface is registered multiple times, it will use the first one specified.
So if you don't uncommment the line your application will resolve implementation since this is the most specific component.
If you do uncomment the line decorator1 will be resolved and indeed the magic starts. The decorator will now start looking for the first registered component that satisfies it's constructor, in this case that would be decorator1 again (you did notice that your output show decorator1 2 times ?). Which will the resolve the next registered component and so on till it comes to the actual implementation.
So the only thing I can think about is not registering decorator1 as an open generic but as a specific type.
Kind regards,
Marwijn.

How to access a Class in the default package from a sub package Class in Flash AS3.0

I got error message when trying to access a class in the default package from the class in its sub package. Can any one help me to sort this out.
FYI, my package structure is A -> B. I meant folder 'A' as default package and 'B' as sub package.
Thanks in advance.
Just create a object of Class A, and call class instance method, from its object.
var classAObj:A = new A();
classObj.MethodA();
I think what you're looking for is for class B to extend class A. That would look something like this in your code:
package main
{
class B extends A
{
// Code here...
}
}
Having code inside packages does not in general affect functionality, it's more an organizational tool. (Except for the internal keyword.)
how about private, protected and public ? I could not see any explanation in the other answers so here it is.
class A
{
private var _password:String;
public var username:String;
protected var serverURL:String;
public function login():void
{
// some code
callServerForLogin();
}
protected function callServerForLogin():void
{
// some code
}
}
class B extends A
{
public function B()
{
var parentPassword = super._password;
// FAILS because private and accessible only inside class A
var parentUsername = super.username
// all ok in here, public property
var parentServerURL = super.serverURL;
// all ok, because it is protected
// also we can call super.login(); or super.callServerForLogin();
}
// IMPORTANT we are also allowed to override public and protected functions
override public function login():void
{
super.login();
// we call the parent function to prevent loosing functionality;
Alert.show("Login called from class B");
}
override protected function callServerForLogin():void
{
super.callServerForLogin();
// keep also parent logic
Alert.show("calling protected method from B");
}
}
// ---- Now considering you declare an object of type B you can do the following
var bObj:B = new B();
// access public properties and call public functions from both B and A
bObj.username = "superhero";
bObj.login();
// will get compile error for next lines
bObj.serverURL = "host.port";
bObj.callServerForLogin();