As you probably know, abstract classes are not a language feature of ActionScript 3. If you are unfamiliar with the concept of an abstract class, let me explain. Think of an abstract class as a super-powered interface. It defines a series of functions that must be implemented, and it cannot be instantiated directly. It goes a step beyond an interface because it also defines some functions that are already fully implemented.
To use an analogy, all electronic devices generally have the same connector to plug into the wall. However, not all electronics have the same purpose. A coffee maker and a DVD player do very different things. We could make an interface IElectronicDevice to make sure they all have a plugIntoWall() function, but then every device will need to re-implement the common wall plug functionality that doesn’t differ very often. By making a class AbstractElectronicDevice, we can implement the wall plug functionality once, and all subclasses of AbstractElectronicDevice will be able to use it without re-implementing the same code.
The problem, of course, is that the coffee maker and DVD player have different controls for turning power on and off. The coffee maker might have a switch, while the DVD player has a button. We can’t implement the togglePower() function in AbstractElectronicDevice because many electronics will have different controls, so we need some way to force all subclasses of AbstractElectronicDevice to implement this function themselves. Using the methods developed to enforce Singletons in ActionScript 3 as a guide, I’ve found a way to enforce the abstractness of a class at runtime upon instantiation.
There are two main parts to enforcing an abstract class. First, we must stop a developer from instantiating the abstract class directly. To do this, the constructor needs a little special sauce. Since anyone can create an instance of a public class by simply using the new keyword, we need the constructor of our abstract class to require a parameter that only subclasses will be able to pass. Second, we must ensure that a developer implements functions that the abstract class has defined, but not implemented.
Stopping Direct Instantiation of an Abstract Class
The magic bean to stop a developer from instantiating a class directly is one keyword: this
. You don’t have access to an instance of a class until after you call a constructor, so only an instance of a subclass will be able to pass a reference to itself to the super class. Let’s look at some code to help make things clearer.
The instance of MyAbstractType expects to receive a reference to itself as the first parameter in the constructor. If it does not, an error will be thrown.
package com.joshtynjala.abstract { import flash.errors.IllegalOperationError; public class MyAbstractType { public function MyAbstractType(self:MyAbstractType) { if(self != this) { //only a subclass can pass a valid reference to self throw new IllegalOperationError("Abstract class did not receive reference to self. MyAbstractType cannot be instantiated directly."); } } } }
Only MyConcreteType and other subclasses of MyAbstractType will be able to pass a reference to the instance to their super()
constructors. Notice that users of MyConcreteType don’t need to know that it extends an abstract class. The signature of the MyConcreteType’s constructor can be completely different than MyAbstractType.
package com.joshtynjala.abstract { public class MyConcreteType extends MyAbstractType { public function MyConcreteType() { //pass "this" to clear the abstract check super(this); } } }
Forcing Implementation of Functions in Subclasses
Next, like with an interface, we need to force subclasses of our abstract class to implement specific functions. Ideally, we want this enforcement to happen immediately when the object is created (to make bugs visible as early as possible). After we check that the user isn’t trying to instantiate the abstract class directly, we should check to be sure the unimplemented methods are overridden. We can do by checking the results from the flash.utils.describeType()
function against a list of unimplemented methods in the abstract class. Again, a little code should give us a clearer picture.
In MyAbstractType, after we check for a reference to the self parameter, we build a list of unimplemented functions in an Array. Next, we use describeType()
to get a list of the methods declared in the instance. If a subclass of MyAbstractType overrides a method, the declaredBy
attribute in the method XML will specify the name of the subclass rather than MyAbstractType.
package com.joshtynjala.abstract { import flash.errors.IllegalOperationError; import flash.utils.describeType; import flash.utils.getQualifiedClassName; public class MyAbstractType { public function MyAbstractType(self:MyAbstractType) { if(self != this) { //only a subclass can pass a valid reference to self throw new IllegalOperationError("Abstract class did not receive reference to self. MyAbstractType cannot be instantiated directly."); } //these functions MUST be implemented in subclasses var unimplemented:Array = [mustBeOverridden]; //get the fully-qualified name the abstract class var abstractTypeName:String = getQualifiedClassName(MyAbstractType); //get a list of all the methods declared by the abstract class //if a subclass overrides a function, declaredBy will contain the subclass name var selfDescription:XML = describeType(this); var methods:XMLList = selfDescription.method.(@declaredBy == abstractTypeName && unimplemented.indexOf(this[@name]) >= 0); if(methods.length() > 0) { //we'll only get here if the function is still unimplemented var concreteTypeName:String = getQualifiedClassName(this); throw new IllegalOperationError("Function " + methods[0].@name + " from abstract class " + abstractTypeName + " has not been implemented by subclass " + concreteTypeName); } } //implemented public function alreadyImplemented():void { trace("Don't forget to list me in the Array of valid functions."); } //unimplemented public function mustBeOverridden(param:String):void {}; } }
Now, in MyConcreteType, we can implement the mustBeOverridden()
function. If we do not, an error will be thrown. To be certain, try commenting out the implementation of mustBeOverridden()
in MyConcreteClass. If you instantiate it, you will receive a runtime error.
package com.joshtynjala.abstract { public class MyConcreteType extends MyAbstractType { public function MyConcreteType() { //pass "this" to clear the abstract check super(this); } //implemented override public function mustBeOverridden(param:String):void { trace("param:", param); } } }
Conclusions
As you probably noticed, the first part of implementing an abstract class is very simple. Making the abstract class receive a reference to itself enforces subclassing, and it can be done in only a few lines of code. The second part, making an abstract class work like an interface, requires a lot more code, and it may be more prone to errors. You, as a developer, must remember to add all the unimplemented methods to the Array in the constructor. Additionally, if the class gets large, I can imagine that calling describeType()
often enough could lead to performance problems. In most cases, as long as you keep your classes clean, it should work well. I highly recommend the subclass enforcement, but I wouldn’t be heartbroken if you feel that checking for unimplemented methods is overkill.
Source code for this tutorial is available for download. It includes all the code above plus an extra implementation (for comparison) of the “electronic device” example I described at the beginning. It’s all under the terms of the MIT license.
I think I’m against trying to force AS3 to have language features it just doesn’t have. Especially because most of these solutions utilize runtime exceptions like this, which is not what a native language feature would do. It would just fail to compile.
I agree, to a certain extent, Keith. Arguably, if you want a class to be a singleton or an abstract class, you can easily treat that class like either without any sort of enforcement. With a little documentation if you’re working with other developers, it’s easy. In the first draft of this post, I referred to the method of creating singletons in AS3 a hack. I meant it as a simple comparison. This is also a hack. No denial there.
On the other hand, I knew people would be interested. When singletons in AS3 were first introduced, there was a lot of interesting discussion, and I wanted to start a dialog. There are many developers out there who want to push non-native features like singletons and abstract classes into their daily development because these features can be useful at times.
I agree that runtime exceptions aren’t ideal, but as long as they stick to the constructor, they’re probably the best bet. Thanks for your thoughts, Keith. I appreciate it.
‘I agree, to a certain extent, Keith. Arguably, if you want a class to be a singleton or an abstract class, you can easily treat that class like either without any sort of enforcement. With a little documentation if you’re working with other developers, it’s easy. In the first draft of this post, I referred to the method of creating singletons in AS3 a hack. I meant it as a simple comparison. This is also a hack. No denial there.’
Thats true but it also makes sense to me to enforce these kind of things, so no matter how much documentation or discuss has been had, mistakes cannot be made. I’d rather my app throw and runtime error, than it do nothing at all and therefore fall over silently.
Pingback: Abstrakte Klassen in AS3 at flash und so…
That was very educative and interesting.
Thanks a lot Josh.
Before even reading any of the other comments, my thoughts were the same as Keith’s. Although the singleton hack is one that I could see myself using on the right occasion, this one seems a bit much. Verifying the functions seems like it could eventually become a hard cpu hit; but not verifying the functions means that you don’t really have the power of an abstract class.
It seems like the real solution is to cry loud enough till Adobe/Ecma gives us Singletons, abstract classes, etc…
I do, however, tip my hat to you for your ability to think outside the box and come up with such creative hack 🙂
Thanks for your thoughts, Nate. I know I would definitely like to see abstract classes and less hacky support for singletons in ECMAScript.
For the record, I’ll personally probably only use the no-instantiation part of my code most of the time when I need abstract classes. With only a couple lines of code to set up, it’s better than no checks at all, which is what I’ve seen from most classes that are considered abstract by a developer (such as those I’ve seen so far in ActionScript 3.0 Design Patterns, an excellent book).
I wrote a small utility class that throws a runtime error using this same type introspection method back in May.
I do agree with Keith that it would be nice if one could throw a compile time error rather than a runtime exception as there is probably a big performance hit when checking an XML file using E4X during class initialization.
Thanks for pointing that out Chandima. Great minds think alike and all that. I also followed some links and noticed that both Tink and Mims Wright have explored this area too. I guess I never noticed. Thanks for sharing! 🙂
It seems to me that the E4X usage may not be a major performance hit. It’s possible, though. I think I’ll try to do a follow up with some measurements to clear up or confirm this worry that we’ve all expressed.
Hi I have a another version of abstract class, my version do not check all the abstract function whether or not be overridden at initial time, but just verify it when you invoke it.
p.s. Just read the codes, don’t be disturbed by Chinese just ignore it.:)
Thanks for sharing, Jeff. During my planning, I considered implementing it like that, but I thought it would be better to check for overrides as early as possible (the constructor). As I and others have stated, a compile time error would be best, since it informs the user of the class immediately that something went wrong. Having all the runtime checks in the constructor is almost like the compiler check (at least when compared to the unpredictable timing of checking in the functions themselves).
Getting some performance data would indeed be great Jeff. I really don’t see anyone implementing runtime checks for abstract classes (maybe worried about the potential performance hit). Looks like the preferred way to deal with them is to comment the code … // please extend / subclass don’t instantiate etc. However, everything would be much cleaner if they were available. I’ve recently started to use the excellent PureMVC framework and it has several concrete classes that should be treated as abstract (and a few singletons) that are heavily commented.
Much like many singleton workarounds I have seen, it should be noted that MyAbstractClass can still be instantiated by putting ‘null’ in the constructor. A little extra code could make it throw an error on null as well.
Daryl, did you read the code? MyAbstractType throws an IllegalOperationError if the parameter is equal to anything but
this
, includingnull
.I guess I hadn’t read it that well and followed the code. Good call.
The only pain (besides the run-time errors) is if I want my MXML class to extend the abstract class I’m not able to use the constructor.
Good call, Bjorn. I hadn’t considered the possibility of using MXML.
I’m looking at it now.
I think I found something although my regexp is not up to scratch..
first couple lines of the AbstractClass.describeType(this) xml output is this.
That should be enough to do the checking that the self constructor reference was used for ?
obviously the xml code is pasted didn’t display well ;P
line 1: type name=”com.qdc.moduleprep::PreperationModule” base=”com.qdc.moduleprep.abstract::AbstractPreparationModule” isDynamic=”false” isFinal=”false” isStatic=”false”
line 2: extendsClass type=”com.qdc.moduleprep.abstract::AbstractPreparationModule”
Pingback: Runtime Enforcement of Abstract Classes in AS3 | SDFUG
this is a very nice post!
i disagree that functionalities that are available in one language but not in another shouldnt be emulated! Thats a really narrow view.. of course it should stay reasonable. But a statement like that would forbid implementing AOP in java or learning from other language communities.
the only thing i miss above is a more generic solution that also would allow multiple inheritance. for that reason i added two functions. i am not 100% happy with them but may be they will inspire somebody for a smoother solution…
hello,
Great article but I’m a bit confused with the theory behind this concept.
You say :
“It defines a series of functions that must be implemented, and it cannot be instantiated directly. It goes a step beyond an interface because it also defines some functions that are already fully implemented.”
But in O’reilly’s Essential Actionscript 3.0 in the Chapter 6 on inheritance, there is a page “Abstract Not Supported” that, if I understand well, state the opposite. “An abstract class in any class that defines zero, or more abstarct methods”. (…)
Subclasses of an abstract class effectively promises to provide some real code to do a job the abstract class only describes in theory.
(…)
I’ve read some other blogs that describes the uses of Abstract class the way you do.
But that book is a trustable source so Am I missing something?
Thks!
greg, the definition of an abstract class in EAS3 does not contradict my definition.
When I say “it defines a series of functions that must be implemented”, that’s the same as “subclasses of an abstract class effectively promise to provide some real code”.
What is it that you believe describes the opposite?
Hey Greg, I’ve always thought of abstract classes exactly the way Josh describes them. The O’reilly quote doesn’t contradict Josh’s definition in my opinion. An abstract class contains “zero or more” abstract methods as you mention.
You can declare your class as abstract without having any abstract methods inside it. In this case it’s just functioning as a base class, but the compiler prevents anyone from instantiating the base class on it’s own. It would most likely have some regular non-abstract methods though, otherwise it wouldn’t be serving much purpose & you might as well use an interface instead.
If you do have an abstract method in your class, though, as far as I know the whole class becomes abstract whether you declare it that way or not. In fact depending on the language, you may get a compiler error if you try to make a method abstract without also declaring the class as abstract.
I do find abstract classes helpful, check out the abstract factory pattern for one example. It would be nice to see this functionality added to the compiler.
“…most of these solutions utilize runtime exceptions like this, which is not what a native language feature would do. It would just fail to compile”
not at all. this code
var foo:DisplayObject = new DisplayObject
compiles fine, but throws this exception:It appears that this only works if the abstract method is public. Private and protected methods don’t show up in selfDescription.method
Just put an exception in the methods that must be overloaded, and remove that reflection (describeType). Performance solved. Private/protected solved.
Eric, you are right. this will be only a little extra work…
Maybe I’ll combine the two options. I’ll see.
Excellent post. Thanks for sharing. How about adding this function declaration to the abstract class to enforce concrete class implementation :
Excellent post. Thanks for sharing. How about adding this function declaration to the abstract class to enforce concrete class implementation :
protected function doSomething(): void {
throw new IllegalOperationError(“This method must be implemented in the concrete class.”);
}
First, thank you Josh for posting this.
Second,
… is not the same as introspection as it does not produce an error until the function is called — the worst possible case in my mind.
I agree with the other posters when they say that Adobe needs to provide an abstract class naively in the language, however, they do not and there are some things you need abstract classes to do (being a C# programmer professionally I really miss this functionality).
Additionally, I always see a good number of people complaining about the “cost” of introspection. Honestly, I use it a lot and RARELY see a serious performance hit (in which case I disable and find another way). However, I think it is backwards to consider performance first and functionality second (when performance is not necessarily going to be an issue). In my not so humble opinion most developers focus WAY to much on performance given the power of the average PC/Server. After getting your code to work, the important factors in order should be:
1. Reliability
2. Maintainability
3. Performance (this is NOT where most applications fall short or cost money)
On the other hand, I believe the compile time error is important and does address the first 2 issues. Without that, the next best thing is to throw an exception at runtime and as soon as possible. In fact, in my own solution, I use even MORE introspection and find all the classes that extend the “MyConcreteType” at initialization and throw exceptions BEFORE the application even fully starts. This makes development, maintainance, etc pretty easy and adds only a mere second or two to my init process (unlike say drawing the controls which takes much longer =P)
Dont fear introspection! I have seen a lot of slow buggy flash/flex applications and more often than not they are slow because of “clever” UI design decisions.
As with most introspection I found describeType to be pretty expensive, so I recommend caching the results somewhere so that you don’t need to call describeType twice for the same type.
Pingback: Abstract Classes in AS3 at AlecMcE.com
Great Post! i read that in order to use decorator pattern on Sprite/Movie Clip based objects you use a abstract-y class not a inteface def – i will try out your suggestion here
It might be a while ago since you wrote this but still very interesting/inspiring to see someone so dedicated to create an abstract hack. Cool and will try to implement it anytime soon!
Greets
I know this is quite an old post, but just wanted to share a thought after reading through the post and the comments.
You rank importance, in the following manner:
1. Reliability
2. Maintainability
3. Performance (this is NOT where most applications fall short or cost money)
I don’t necessarily disagree with you, however sometimes you do have to sacrifice a lesser “important” bullet point for another.
One way to sort of compromise on this issue would be to set some sort of flag, that way introspection could be turned on/off at will.
Introspection in this case, only benefits you while you are developing. Having runtime introspection happening in a live, production release version of an application does you no good and it will just eat up unnecessary resources.
So, let’s say you have a class, idk, let’s just include this functionality as part of a Debugger class, so you have a static var Debugger.INTROSPECTION_LEVEL = “2”; // 0, 1 or 2
Where 2 would be the highest level of introspection, 1 would be basic level and 0 would be none at all.
This way, after you are done developing and ready to push a build, you just set Debugger.INTROSPECTION_LEVEL = 0 and all the performance issues go away.
Just thought I’d share my two cents.
Pingback: Abstract Base Class
Thanks for a great tutorial! 🙂
Thank you for the tip, very helpfull.
Hi,
There’s a bit simpler way of faking an abstract class.
Cheers.
Like every advanced tutorial, in this also some thing is missing. The answer to question “Why to use it?”
Know this is an oldie, but just figured I’d tag another solution into here that seems to work fine at least in my current version of FB 3.4
In the constructor:
It results in a string comparison and requires no changes to the constructor of the abstract or concrete sub classes. I still have no good solution for finding un-implemented methods, the best I can think of is to break apart the interfaces and have the sub-classes implement a secondary interface which essentially contains what you would consider the unimplemented methods of the abstract class (in essence achieving the goal but with more files than should be necessary and possibility for confusion where abstract classes would make this clear). Also @Zeljko I think there’s a decent explanation of why you would do this above, if you ever use abstract classes in another language such as Java (among other things I miss from Java like overloading) you’d be able to more easily understand why this is really nice to have.
http://download.oracle.com/javase/tutorial/java/IandI/abstract.html
http://www.javacoffeebreak.com/faq/faq0084.html
What it comes down to is the abstract class acts much like an interface requiring certain implementations to be handled by the implementing class, however unlike interfaces, abstract classes can contain some of the functionality. As an alternative to my suggestion of breaking down the interface you could also just create a test case that calls all the methods and in the “abstract” version have it throw an error, create an instance of each concrete class in the test then call all methods of the “abstract” class that require concrete implementation. This avoids the overhead of the run time solution and would help catch errors early, the only caveat is having to use a test framework like flex unit to execute the test class.
Sorry to amend my original post, the class CommonParserBase is my abstract class and this code would live in that classes constructor, essentially saying if an object calls this things constructor it has to be some object typed as something else (that is a subclass).
Similar to Shaun’s solution (requires no special processing in subclasses) but works in Flash Pro as well as FB :
In constructor of MyAbstractClass add:
And rather than maintain an array of abstract methods a unique prefix naming convention could be applied to abstract methods and used to search for them in the reflection. for example if a double underscore prefix (“__”) is used uniquely for abstract method names then during instantiation the following code, implemented in the constructor of MyAbstractClass, will throw an error on the first abstract method it finds which is not implemented in the subclass.
One thing about abstract classes that has been completely ignored so far is that an interface cannot declare Events, Styles etc.
So all the support in Flex Builder and MXML for easy creation of event handlers and style properties fails if your MXML class has a member that is defined by just an interface.
For detection of a direct instantiation, I don’t use a self parameter. I rather compare the class name of the current this pointer with the static class name:
if( flash.utils.getQualifiedClassName(this).substring(2+flash.utils.getQualifiedClassName(this).indexOf(“::”))==”myClassName”) { throw Error…};
Some of my abstract classes contain a static function that instantiates the proper descendant based on additional parameters.
Things would be much easier if you could simply declare the constructor of the base class as protected. All that is to for implementing this is to remove the error check for a non-public constructor from the compiler and it should work as expected. I’m sure the compiler would do the right thing (and throw the right errors) if you only could get past the ‘constructors must be public’ check.
Even a private constructor could be useful, when designing a managed class.
Couldn’t you emulate an abstract class with errors at compile time by splitting the problem in two? Your base class is a normal class which contains all the pre-defined methods. A second (supplementary) class is an interface with all the to-be-implemented methods. The base class REQUIRES that an (implemented) version of the interface is passed in the constructor.
—
Class pseudo-abstract{
private var implementedmethods:IUnimplementedmethods;
public function constructor(implementedClass:IUnimplementedmethods){
this.implementedmethods = implementedClass;
}
public function implementedfunction(){
…code…
}
public function unimplementedmethod(){
implementedmethods.unimplementedmethods();
}
}
—
I’m not an actionscript user, so please excuse my syntax …
Note that you could even emulate overriding by “try{implementedmethods.implementedfunction()}
catch(error){…code…}”
if there’s anything similar available in AS.
Seems like a reasonable approach, Solstice_Of_Light. Usually, what I do these days is create an interface, implement all of its methods in a base class, but leave out the
implements IWhatever
. Then, then subclass needs to do it. Enforcing anything else beyond that amounts to busywork, in my opinion.I understand that this is a really old article, but I’d been doing a bit of quick thinking and while not tested I believe this solution might work a tad bit nicer for deep tree structures of abstract classes sprinkled with leaves of concrete classes (which is the case in my project):
1. For the root abstract class (which is just one of many abstract classes that directly and indirectly extend this), have a protected boolean variable initialised to false that signals whether or not instantiation has succeeded
2. Write an if statement in the root abstract class’ constructor, throwing an error if the boolean is set to false
3. In each concrete class, ignoring all abstract classes inbetween, set this boolean to true and then call the root abstract class’ constructor
Please do feel to mention if this idea is flawed, however I’ll be implementing it in a bit