Monthly Archives: October 2008

The Instantiator: A simple Flex utility class for more powerful skinning in custom components

One thing that bugs me about the core Flex SDK components is that they use the Class datatype for just about everything. From time to time, you encounter the awesomely flexible mx.core.IFactory type for a renderer property, but when it comes to styles, Class is king. The problem is that sometimes I wish I could instantiate a Function object prototype-style. It’s a great way to create new “classes” at runtime.

There’s nothing I can do to fix this limitation in the core components without patching the source manually (I know, I’ve tried several crazy ideas), but when I create a custom component, I can make it much more flexible. The easiest solution, the one I’ve been using most often, is to simply type the style value as Object whenever I use getStyle() for a skin style:

var skinClass:Object = this.getStyle( "skin" );
var skin:DisplayObject = new skinClass();

This allows Function to be used with the new keyword like a Class, which is generally enough for my needs.

However, I also mentioned IFactory earlier. There’s something compelling to me, as a component developer, in the simplicity and power of allowing my developers to use a factory to customize skins. I usually find a decent enough substitute through styleName or the StyleProxy class, but I feel like I’m rewriting the same boring code over and over again whenever I make yet another skin or sub-component styleName style. Don’t get me started on chaining styleNames multiple levels deep. Every time I do it, it feels awesome because I know everything is super-customizable, but I also wonder how many developers understand how these work. Of course, the fact that you can’t create an IFactory in your stylesheets is a problem. One could argue the same thing about using a Function to instantiate a skin, though, but I find a function’s ability to create a runtime datatype through prototype too compelling to ignore. I’m not quite as sure about IFactory, but I feel the option is useful to have, even if I don’t need it too often.

I could always change my instantiation code to look like the following, but I’d hate to repeat these several lines over and over again when I want to build a skinnable component:

var skinBuilder:Object = this.getStyle( "skin" );
var skin:DisplayObject;
if( skinBuilder is IFactory )
{
    skin = IFactory(skinBuilder).newInstance();
}
else
{
    skin = new skinClass();
}

With that much code needing to be repeated across multiple components, it’s starting to scream utility function. A few minutes ago, I came up with the idea for The Instantiator a useful utility for just this situation. Check it out:

var skinBuilder:Object = this.getStyle( "skin" );
var skin:DisplayObject = TheInstantiator.newInstance( skinBuilder );

Basically, you pass in the raw style value, and TheInstantiator will create a new instance if it knows how. If not, then it returns null. Here’s the source for the class:

////////////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2008 Josh Tynjala
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to
//  deal in the Software without restriction, including without limitation the
//  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
//  sell copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
//  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
//  IN THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////

package com.flextoolbox.utils
{
	import flash.utils.getDefinitionByName;

	import mx.core.IFactory;
	import mx.styles.ISimpleStyleClient;

	/**
	 * Utility for creating instances of Flex sub-components or skins.
	 *
	 * @author Josh Tynjala (joshblog.net)
	 */
	public class TheInstantiator
	{
		/**
		 * Creates a new instance of an object. Supports Class, Function, a
		 * fully-qualified class name String, or mx.core.IFactory.
		 *
		 * @param type			The type to instantiate
		 * @param styleName		The styleName to set if the instantiated object supports styles.
		 */
		public static function newInstance(type:Object, styleName:String = null):Object
		{
			var instance:Object = null;

			//first check whether type is a String.
			//if so, try to convert to a class
			if(type is String)
			{
				try
				{
					//will throw an error if it's not a fully qualified class name
					type = getDefinitionByName(type as String);
				}
				catch(error:Error)
				{
					return null;
				}
			}

			//Class and Function may be used with the new keyword
			if(type is Class || type is Function)
			{
				instance = new type();
			}
			else if(type is IFactory)
			{
				//mmmmm... factories are great
				instance = IFactory(type).newInstance();
			}

			//if the new instance supports styles, set the styleName property.
			if(instance is ISimpleStyleClient)
			{
				ISimpleStyleClient(instance).styleName = styleName;
			}

			return instance;
		}
	}
}

You’ll also notice a couple extras. First, you can also pass in a fully-qualified class name as a String value, and it will automatically retrieve the proper class to use, or it will return null if it fails to find the class. Second, I defined an optional styleName argument. Since setting style names is often part of creating a new instance of a skin or a sub-component, it’s easy to get this done at the same time and save a couple lines of code. There’s a check for whether the instantiated object is an ISimpleStyleClient, which is Flex’s interface for display objects that support styleName, so nothing should go wrong if the object doesn’t support styles.

You know, reading this all over again now, I think it would be great if ActionScript defined an interface for datatypes that could be instantiated with the new keyword. Class, Function, and even Flex’s IFactory could implement it, and developers could create their own factory-like classes that could be used in place of Class with the new keyword. That almost smells like a feature request….

Cole's Learning Flex 3 perfect for newbie Flex developers

Though I haven’t had much time for reading lately, I recently finished Learning Flex 3 by Alaric Cole. It’s a solid introduction to Flex, and while it doesn’t get too heavy on the intimate details of the Flex framework, I can definitely recommend it for people who are looking at Flex for the first time. The flow throughout the book is unique, and if you combine that with the stylish design, it’s an excellent read for a new Flex developer.

Cole’s writing style is clear and friendly, and he carefully introduces new features as they’re needed in his example applications. It’s a bit different from the progression I’ve seen in other programming books, but I found it refreshing and interesting in a way that I think will keep most readers interested. As with any programming book, I’m happy when I learn something new, and Alaric had some interesting tips for features in Flex Builder’s Design View that I’d never used (like highlighting container bounds). I tend to stick to the Code View as much as possible myself, but it’s still good to know.

My absolute favorite part about the book is the full-color content on every single page. Like Learning ActionScript 3.0, another Adobe Developer Library book by O’Reilly which I reviewed previously, the addition of color makes the book stand out from the pack. Every Flash or Flex book I’ve read in the past has included black and white screenshots. With RIA content being very much about visual appeal and design-heavy details, it makes sense to ensure that all visual references in the book are in color. I remember a couple books that I read previously where screenshots were useless because they didn’t make the greyscale transition very well. Learning Flex 3 continues to set a new standard for Flash and Flex books.

One thing Cole doesn’t focus on much is the language syntax for ActionScript 3.0. This is a book specifically about getting started with Flex, and you’re expected to know a bit about programming already. I personally enjoy this aspect because I’m tired of seeing yet another “This is a variable. This is a loop. This is a class.” introductory chapter. However, for true newbies, the lack of an AS3 introduction could make getting started a challenge. I already mentioned Learning ActionScript 3.0, and I assure you that it covers all the missing details. If you’re new to software development and programming, consider picking up both books since they offer a more comprehensive introduction for someone completely new to programming with either AS3 or Flex.

Full disclosure: When I worked at Yahoo!, Alaric and I had neighboring desks. Don’t let that stop you from taking my recommendation, though. Learning Flex 3 is a solid book for someone completely new to developing with Flex. If you have a bit of experience already, though, a more intermediate book like Programming Flex 3 might be a better choice. If you’re interested, I wrote a review of the Flex 2 version.

I see your privates: How objects of the same class can share private variables in AS3

Today, I was surprised to discover something that I didn’t know about private variables in AS3. If an instance of class A has a reference to another instance of class A, then the second object’s private variables are accessible to the first object. No restrictions. No special tricks. You just use obj.variableName like any other property request. I’ll show you some example code, and you can try it yourself.

First, let’s set up the situation. Alice has a secret in her diary. Trudy wants to know Alice’s secret, so she’s going to sneak in and take a peek. Here’s a simple document class that presents our story in code:

package
{
	import flash.display.Sprite;

	public class ISeeYourPrivates extends Sprite
	{
		public function ISeeYourPrivates()
		{
			//the intruder
			var trudy:Person = new Person("Trudy");

			//the victim
			var alice:Person = new Person("Alice", "I kissed a girl, and I liked it!");

			//Trudy is curious, and she wants to read Alice's diary
			trudy.peekIntoDiary(alice);
		}
	}
}

Finally, this UML-like diagram below also shows what’s happening:

UML-like diagram. Alice and Trudy are instances of Person. Through peekIntoDiary(), Trudy can access Alice's private variable _secret.

Next, let’s look at the Person class and see how the peekIntoDiary() method works:

package
{
	public class Person
	{
		public function Person(name:String, secret:String = null)
		{
			this.name = name;
			this._secret = secret;
		}

		public function peekIntoDiary(target:Person):void
		{
			trace(this.name, "is looking at ", target.name + "'s secret:", "\"" + target._secret + "\"");
		}

		public var name:String;
		private var _secret:String;
	}
}

As you can see the secret value sent to the constructor gets stored in the private variable _secret. Another Person instance is passed to the peekIntoDiary() method. In this case, the Trudy object (this) now has access to the Alice object (target). The trace() output reads:

Trudy is looking at Alice’s secret: “I kissed a girl, and I liked it!”

Yes, Alice’s private variable _secret has just been accessed by Trudy. Bet you didn’t expect that to work. I know I didn’t. Don’t believe me? Try it yourself. The code above compiles and runs.

It makes some sense if you consider that the private access modifier is actually a namespace. Basically, behind the scenes, the compiler automatically creates a separate namespace for each individual class that it names private. This private namespace is only accessible to the one class for which it is defined. That’s why other classes and subclasses can’t access private variables. However, due to the scope of the namespace, all instances of the same class can access the private members of other instances. To be truly private, each individual instance of a class would needs its own namespace that other instances wouldn’t know about. I’m not even sure if that’s possible, but I have a vague idea of how it might work.

Does it matter? No, not really. You’ll rarely find yourself in an situation where this behavior can be useful (see the credited link below for one possibility). I can’t think of a case where this can be considered a security risk either. It’s not much different than using object["variableName"] to get at private variables in AS2. Mainly, I wanted to share because it’s somewhat unexpected behavior.

Credit: Thanks to Nick Bilyk for pointing this out in a post about cloning objects.