inicio mail me! sindicaci;ón

Archive for July, 2008

Inheritence and variables in Actionscript 3.0

I am working on a lot of framework type stuff right now and ran into an interesting...I don't want to say "problem." Let's say "hurdle." I had worked out a base class for scrollbars (screw the AS 3.0 component library) and wanted to keep my base class light and fast. Seriously, stay light and fast with your framework components. If you want to write a framework where the base classes can compete in the Olympics - don't bother. Just use Flex. But if you want light and fast - write it yourself and be smart.

Anyway, the idea was to keep the base classes really light but easy to extend. In the case of scrollBars, the functionality is not changing for any subclass - just the skins and the animation. I love the protected attribute for properties and methods in base classes. Your subclasses will be able to access anything and override what needs to be overridden. I simplified version of the base class is below.

package
{
	public class ScrollBar extends MovieClip
	{
		public function ScrollBar()
		{
			super();
 
			createChildren();
 
			addChild( scrollTrack );
			addChild( scrollArrow1 );
			addChild( scrollArrow2 );
			addChild( scrollThumb );
		}
 
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
 
		protected var scrollArrow1 : ScrollArrow;
		protected var scrollArrow2 : ScrollArrow;
		protected var scrollThumb : ScrollThumb;
		protected var scrollTrack : ScrollTrack;
 
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
 
		//--------------------------------------------------------------------------
		//  createChildren
		//--------------------------------------------------------------------------
 
		/**
		 *  @protected
		 *  Creates the default children of the ScrollBar.  Meant to be overridden when
		 *  the scrollBar has been reskinned.
		 */
		protected function createChildren () : void
		{
			// up arrow
			scrollArrow1 = new ScrollArrow();
			// down arrow
			scrollArrow2 = new ScrollArrow( ScrollArrow.DOWN );
			// scroll track
			scrollTrack = new ScrollTrack();
			// scroll thumb
			scrollThumb = new ScrollThumb();
		}
 
	}
}

The hurdle came up when I tried to override a protected variable in a subclass. it would be great to just say:

package
{
	public class CoolerScrollBar extends ScrollBar
	{
		public function CoolerScrollBar ()
		{
			super();
		}
 
		//--------------------------------------------------------------------------
		//
		//  Properties
		//
		//--------------------------------------------------------------------------
 
		override protected var scrollArrow1 : CoolerScrollArrow;
		override protected var scrollArrow2 : CoolerScrollArrow;
		override protected var scrollThumb : CoolerScrollThumb;
		override protected var scrollTrack : CoolerScrollTrack;
	}
}
 

This is NOT allowed. In Actiosncript 2, we could override whatever we wanted - just redeclare the variable and it would take over whatever you were overriding. AS 3 gives us an "incompatible override" compiler error. Initially I found this frustrating - I did not want to take the time to cast all these variables and I didn't want to clog up a base class and sub classes with extra methods. The solution to this is easier than all of that pain and makes sense when you think about. The code:

 
package
{
	public class CoolerScrollBar extends ScrollBar
	{
		public function ScrollBar()
		{
			super();
 
			createChildren();
 
			addChild( scrollTrack );
			addChild( scrollArrow1 );
			addChild( scrollArrow2 );
			addChild( scrollThumb );
		}
 
		//--------------------------------------------------------------------------
		//
		//  Methods
		//
		//--------------------------------------------------------------------------
 
		//--------------------------------------------------------------------------
		//  createChildren
		//--------------------------------------------------------------------------
 
		/**
		 *  overridden
		 */
		override protected function createChildren () : void
		{
			// up arrow
			scrollArrow1 = new CoolerScrollArrow();
			// down arrow
			scrollArrow2 = new CoolerScrollArrow( ScrollArrow.DOWN );
			// scroll track
			scrollTrack = new CoolerScrollTrack();
			// scroll thumb
			scrollThumb = new CoolerScrollThumb();
		}
 
	}
}
 

This code works as long as the CoolerScrollArrow is a subclass of ScrollArrow. It is just that simple (and you can see why having methods like createChildren are great for base classes - so handy when extending later on).

Why do I find this better than the days of Actionscript 2? Well, the compiler can still police us a bit. If you try to assign say, BlueButton to one of those variables, and BlueButton only extends Sprite and not ScrollArrow - you get an error right in FTD and can't even compile ("You cannot assign 'BlueButton' to an 'ScrollArrow'..."). If we could override anything we want, we would probably break our base class quickly by changing something to a data type where key properties and methods don't exist.