Runtime Enforcement of Abstract Classes in AS3

by Josh Tynjala

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.

About the Author

Josh Tynjala is an indie game developer, entrepreneur, Flash and Flex mercenary, and bowler hat enthusiast.

Discussion
  1. 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.

    posted by Keith Peters on 08.19.2007
  2. 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.

    posted by Josh Tynjala on 08.20.2007
  3. ‘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.

    posted by Tink on 08.20.2007
  4. [...] zeuslab gibt es aber nun einen Artikel der eine Möglichkeit beschreibt dieses zu Simulieren. [...]

    posted by Abstrakte Klassen in AS3 at flash und so… on 08.20.2007
  5. That was very educative and interesting.

    Thanks a lot Josh.

    posted by Boubalou on 08.20.2007
  6. 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 :)

    posted by Nate Chatellier on 08.20.2007
  7. 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).

    posted by Josh Tynjala on 08.20.2007
  8. 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.

    posted by Chandima Cumaranatunge on 08.20.2007
  9. 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.

    posted by Josh Tynjala on 08.20.2007
  10. 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.:)

    posted by Jeff on 08.21.2007
  11. 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).

    posted by Josh Tynjala on 08.21.2007
  12. 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.

    posted by Chandima Cumaranatunge on 08.26.2007
  13. 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.

    posted by Daryl Ducharme on 09.21.2007
  14. Daryl, did you read the code? MyAbstractType throws an IllegalOperationError if the parameter is equal to anything but this, including null.

    posted by Josh Tynjala on 09.21.2007
  15. I guess I hadn’t read it that well and followed the code. Good call.

    posted by Daryl Ducharme on 11.06.2007
  16. 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.

    posted by Bjorn on 01.02.2008
  17. Good call, Bjorn. I hadn’t considered the possibility of using MXML.

    posted by Josh Tynjala on 01.02.2008
  18. 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 ?

    posted by Bjorn on 01.02.2008
  19. 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”

    posted by Bjorn on 01.02.2008
  20. [...] Check it out here: Astract Classes in AS3 [...]

    posted by Runtime Enforcement of Abstract Classes in AS3 | SDFUG on 01.11.2008
  21. 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…

    /**
     * Note: use this function to create or add methods that needed to be implemented!
     * example: super(self,abstractMethods("ClassName",["methodAName","methodBName"]))
     *
     * @param abs passed list of abstract methods
     * @param clazz name of the class defining the abstract classes
     * @param methods list of all methods
     * @return list of all abstract methods that are not implemented
     */
    protected function abstractMethods(clazz:String,methods:Array,abs:XMLList=null):XMLList{
    	var t:XML = ;
    	for each(var s:String in methods)
    		t.appendChild();
    	if(abs==null)
    		abs = XMLList(t);
    	else
    		abs += t;
    	return abs;
    }
    
    /**
     * @param abstract list of methods to implement
     * @param implemented list of methods implemented
     * @return a list of methods that are not implemented
     */
    private function _checkMethods(implemented:XMLList,abstract:XMLList):XMLList{
    	var found:XMLList;
    	var match:XMLList;
    	for each(var type:XML in abstract){
    		for each(var method:String in type['method'].@name){
    			match = implemented.(@name==method &&  @declaredBy==type.@name);
    			if(match.length()>0){
    				if(found==null)
    					found = match;
    				else
    					found += match;
    			}
    		}
    	}
    	return found;
    }
    posted by Niels Wolf on 03.06.2008
  22. 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!

    posted by greg on 04.03.2008
  23. 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?

    posted by Josh Tynjala on 04.03.2008
  24. 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.

    posted by Jason on 09.11.2008
  25. “…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:

    ArgumentError: Error #2012: DisplayObject$ class cannot be instantiated.
    posted by makc on 09.18.2008
  26. It appears that this only works if the abstract method is public. Private and protected methods don’t show up in selfDescription.method

    posted by Ed on 10.23.2008
  27. Just put an exception in the methods that must be overloaded, and remove that reflection (describeType). Performance solved. Private/protected solved.

    posted by Eric Muyser on 11.11.2008
  28. Eric, you are right. this will be only a little extra work…
    Maybe I’ll combine the two options. I’ll see.

    posted by Dykam on 12.11.2008
  29. 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.");
    }
    posted by Joe B. on 02.19.2009
  30. 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.”);
    }

    posted by Joe B. on 02.19.2009
  31. First, thank you Josh for posting this.

    Second,

    protected function doSomething(): void
    {
     throw new IllegalOperationError(”This method must be implemented in the concrete class.”);
    }

    … 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.

    posted by Michael on 03.06.2009
  32. 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.

    posted by Phi on 04.16.2009
  33. [...] Self Reference Approach @ JoshTalksFlash [...]

    posted by Abstract Classes in AS3 at AlecMcE.com on 07.29.2009
  34. 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

    posted by mikew909 on 09.07.2009
  35. 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

    posted by Jochen Szostek on 01.14.2010
  36. 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.

    posted by Taka Kojima on 03.26.2010
  37. [...] mentioned by josh tynjala in Runtime Enforcement of Abstract Classes in AS3, abstract classes is not a feature of actionscript 3. in his section forcing implementation of [...]

    posted by Abstract Base Class on 05.31.2010
Share Your Thoughts

To display code in comments: <pre>Code here. May be multiline. Format XML with &gt; and &lt; entities.</pre>

Some HTML allowed in comments: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>