How can I subclass a class loaded from a swf - actionscript-3

I want to subclass "superClass" and override one of it's functions.
public class superClass {
protected function f1(...) : Boolean {...}
protected function f2(...) : Boolean {...}
...
protected function f100(...) : Boolean {...}
}
public class subClass extends superClass {
// override f1 in the subclass
protected override function f1(...) : Boolean {...}
}
The problem is that the "superClass" is loaded from a swf. I do not have a reference to the class definition in my project. Is there a way to do something like below?
public class subClass {
private var superClassObject: Object;
// construct from an instance of superClass
public function subClass (s : Object) {
superClassObject = s;
}
private function myF1(...) : Boolean {...}
override InvokeFunction (fname: string, args: Array) : Object {
if (fname == "f1") {
return myF1(args);
} else {
return superClassObject.InvokeFunction(fname, args);
}
}
}
I'm not sure how function call is implemented in AS. What should "InvokeFunction" be?

You should use .swc , not .swf. The class you want to extend must be available at compile time, not at runtime. Anyway if using of swf is mandatory for you, you could use different techniques to 'override' functionality.
Besides inheritance there are other OOP concepts (Composition, Aggregation,etc...) and design patterns(Proxy,Adapter,etc...) for changing functionality of class. You could use them.

Related

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.

How to enforce derived classes to implement methods in AS3?

I have a rather simple theoretical question regarding OOP (in AS3) that I don't know how to google:
I need something like an abstract class, which would require that dependant class implements some interface, like this:
Interface ISomething
{
public function somethingize(otherThing:type):void;
}
abstract public class AbstractSomething implements ISomething
{
public function AbstractSomething()
{
// ...
}
public function doSomething():void
{
//code here
// ...
this.somethingize();
// ...
}
}
Is the only way to achieve such a thing is to drop an "abstract" keyword, and move somethingize to SomethingWrapper (with an implementation of throwing an "unimplemented exception"), or is there some better way to model it?
ActionScript doesnt support Abstract classes (unfortunately).
I think there are a few techniques out there to try and mimic abstracts, but my way is too just throw errors in my abstract classes to stop them being used directly, eg:
public class AbstractSomething implements ISomething
{
public function AbstractSomething()
{
throw new Error("this is an abstract class. override constructor in subclass");
}
public function doSomething():void
{
throw new Error("this is an abstract class. override doSomething in subclass");
}
}
Without more information about the specific implementation, I would prefer composition over inheritance in this case, specifically dependency injection.
public interface ISomething {
function somethingize(thing:*):void;
}
public class SomeWorker {
private var _something:ISomething;
public function SomeWorker(something:ISomething) {
this._something = something;
}
public function doSomething():void {
// work
this._something.somethingize(obj);
// more work
}
}
Inherrited classes of SomeWorker could inject the correct implementation of ISomething for the work they need to do, or that dependency could be resolved somewhere else.

How to Override Constants in ActionScript 3

I have the two following classes:
public class Parent{
static internal const _name:String = "Parent";
public function get name():String{
return _name;
}
}
public class Child{
static internal const _name:String = "Child";
}
If I create an instance of class Child and call its name() getter, since it will call the name() method it inherits from Parent, it returns "Parent". I could, of course, override the name() method:
public class Child{
static internal const _name:String = "Child";
override public function get name():String{
return _name;
}
}
That returns "Child". However, it seems silly to have to copy the exact same code of the method from the parent. Is there any simpler way to do this?
I would take a different approach by making the "name" property a requirement for the parent's constructor:
public class Parent
{
static internal var _name : String;
public function Parent(name : String = "Parent") {
_name = name;
}
public function get name() : String {
return _name;
}
}
Child Class:
public class Child extends Parent
{
public function Child() {
super("Child");
}
}
Firstly, you cannot override static methods or properties - they are not inherited, so no override for them.
Secondly, if you declared a constant to be of a complex type, it is not really a constant. I.e. if it is an object, then you can change its keys / values, if it is an array, you can add / remove members and so on.
But the desire to make this functionality more generic is understandable. So, what I'd do:
Have some property outside both parent and child, let say in class X, or package Y. Let it be package Y. So, you'd create a dictionary in package Y, let it be Y.names and in your name getter you'd do:
import Y.names;
. . .
public function get name() {
return names[(this as Object).constructor];
}
your names variable would be:
package Y {
public var names:Dictionary = generateNames();
internal function generateNames():Dictionary {
var result:Dictionary = new Dictionary();
result[ChildClass] = "child";
result[ParentClass] = "parent";
. . .
return result;
}
}
This way it would be sufficient to only implement name getter in super-class, and all inheriting classes will be able to use super-class code as is, no need to change anything. However, this means that some (maybe important) information pertaining to this class will be stored elsewhere (may be difficult to find, this is not the common way people program in AS3).
your implementation of get name should look like this, then the getter is one and each of the new classes needs to have it's own public static var _name defined:
//in the base class
public function get name():String
{
var _sName:String;
if ((this as Object).constructor._name)
{
_sName = (this as Object).constructor._name;
}
else
{
try
{
var o:Object = getSuperClass(this);
while (o)
{
if (o._name)
{
_sName = o._name;
break;
}
o = getSuperClass(o);
}
}
catch (e:*)
{}
}
return _sName;
}
//as found here: http://www.actionscriptdeveloper.co.uk/getting-the-class-of-an-object-in-as3/
public static function getSuperClass(o: Object): Object
{
var n: String = getQualifiedSuperclassName(o);
if (n == null)
return(null);
return getDefinitionByName(n);
}
the static members can be accessed only via class reference which we can get from constructor object, "this" will point to the current class in the inheritance chain so you can call this in parent class and it will point to a Child in a Child class.
[EDIT]
I've modified it so it tests for existance of the public static property _name if not found on "this" instance then in a loop the parent class is checked until one is found - like inheritance:)
I'm using this feature to create clone method: constructor as helper in clone method implementation
best regards
Why don't you store such a constant within a corresponding function instead of declaring an inaccessible constant?
class Parent {
...
public function get name():String { return 'Parent'; }
}
class Child extends Parent {
...
override public function get name():String { return 'Child'; }
}
By the way, if your Parent class is a descendant of DisplayObject, you should be careful with name property, as it's needed sometimes by operating code, e.g. getChildByName().
I have found something that seems to work. Any feedback is greatly appreciated:
public class Parent{
prototype._name = "Parent";
public function get name():String{
return this["_name"];
}
}
public class Child{
prototype._name = "Child";
}

AS3 Inheritance

When 'SubClass' extends 'SuperClass', when it inherit its methods and properties, it creates methods and properties that distinguishes from the 'SuperClass'?
Or if I create an instance of 'SubClass' and I try to modify a property, that was inherited from 'SuperClass', am I modificating the super class property also?
Thanks.
EDIT
package {
public class SubClass extends SuperClass {
public function SubClass() {
trace('superclass value n='+superClass.n+'\n');
trace('subclass changes inherited n'+'\n');
n = 3;
trace('subclass value n='+n+'\n');
trace('superclass value n='+superClass.n+'\n');
}
}
}
Returns me:
superclass value n=-1;
subclass changes inherited n;
subclass value n=3;
superclass value n=3;
I will explain it in short.
We have two classes - Subclass and SuperClass.
SuperClass have four methods:
private function methodPrivate():void;
protected function methodProtected():void;
public function methodPublic():void;
internal function methodInternal():void;
From the Subclass you:
Cannot access methodPrivate():void;
Can access methodProtected():void; but just like your private method, it means, you cannot access it from outside of Subclass.
Can access methodPublic():void; and everything can access if from outside of Subclass also.
methodInternal():void; is available for classes from the package of SuperClass.
You can however override these methods. Overriding doesn't change a methods of SuperClass but change them only in SubClass.
override public function methodPublic() : void {
// your additional code
super.methodPublic(); // eventually calling the same method of SuperClass, you can pass arguments to it also
}
As you know, your SuperClass can also have variables, that also can be public, protected, private or internal. You cannot override them, but you can do this with getters or setters however.
You can access variables that are created as public or protected by using a word "super" like this: super.someVariable .
So everything is up to you, if you want to create a different variables of the same name in SuperClass and SubClass, just declare one as private in SuperClass. If you want to have one variable that SuperClass and SubClass both can access - just declare it as protected or public.
Hope that was clear.
When you create a blank SubClass the extends SuperClass, you are creating a new class that provides the same interface (with the same implementation) to the parent class.
That is to say, if your parent class contains a method doSomething, your SubClass, without ever actually writing it, will have the doSomething method available as well. The one caveat to this is if the method is marked private, in which case the inheriting class, SubClass, will not have access.
package {
public class SuperClass {
public function SuperClass():void {
self.doSomething();
}
public function doSomething():void {
trace("doing something");
}
}
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
}
}
Once you have this relationship established, you can decide whether calling doSomething on an instance of SubClass will behave differently than the default implementation, defined in SuperClass. If you want the same behavior, you leave it as is. If you want different behavior, then you override the parent class' method, using the keyword override.
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
override public function doSomething():void {
trace("doing another thing instead");
}
}
}
Now something that calls doSomething on an instance of SubClass will get modified behavior. But the default implementation has not been touched. Instanced of SuperClass are not modified by this overriding of a method. Only instances of SubClass will be affected.
This is the same case for properties.
There is one exception to this, and that is static properties. A static property is a property of the class, not of an instance of the class. Static properties are not inherited. A static property looks like this:
package {
public class SuperClass {
public static var i:int = 0;
public function SuperClass():void {
}
public function doSomething():void {
trace("doing something");
}
}
The SubClass class will not have a reference to a static property i. However, a SubClass instance can change the static value of the SuperClass. As an example:
package {
import SuperClass;
public class SubClass extends SuperClass {
public function SubClass():void {}
override public function doSomething():void {
trace("changing something in SuperClass");
SuperClass.i = 1;
}
}
}
Now, the SuperClass's static variable i has a value of 1, instead of 0. In this way a SubClass has the potential (although it is the same potential any code has with the right access privileges) to change the properties of SuperClass.
I hope this helps.

Overriding a public variable with set

I have a base class like this
class Base {
public var space:Number;
}
which gets extended by
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
This doesn't compile. Say, you don't have control of the base class, what ways is there implement the same thing?
The obvious is create a function setSpace(), but this object is being embedded in an already existing system that use the public space.
Thanks in advance.
Your base class should be defined that way:
class Base {
// Don't use public variables. Make them private and define setters and getters
private var space_:Number;
public function get space():Number {
return space_;
}
public function set space(v:Number):void {
if (space_ === v) return;
space_ = v;
}
}
And then it can be overriden that way:
class Desc extends Base {
override public function set space( space:Number ):void {
//code
}
}
Edit:
I missed the part where you say you don't have control over the base class. In that case, hope that space is defined as a getter/setter (it should be if the class is implemented properly). If not, you'll indeed have to use a function such as getSpace and setSpace.
From Adobe:
Class member variables that are declared using the var keyword cannot
be overridden in a subclass.
Using a setter is not an option in your case. If you need to preserve the interface, use composition instead of inheritance:
class Desc {
private var _base:Base;
public function set space(space:Number):void {
//code
this._base.space = space;
}
}