Let’s face it: The client has not been a friendly place for Java programmers. Java technology on the client with applets, Swing, and JavaFX has had limited success. JavaScript, despite its name, is almost nothing like the Java language. And Adobe Flash—well, it’s just like JavaScript. Or is it? It might have been the case that Flash was like JavaScript a couple of years ago, but with the advent of ActionScript 3, a lot has changed. And I think you’ll find a lot to like.
First, ActionScript—the programming language for Adobe Flex and Flash—is now strongly typed. It also has first-class object orientation, including classes and interfaces. It has extras that you won’t find in Java—notably, get
and set
functions for properties and a language extension called ECMAScript for XML (E4X), which turns any XML document into objects that you can reference with dot operators, just like regular objects.
This article takes you through the basics of ActionScript 3 and shows how it compares with the Java environment you’re used to. By the end, you should have given up any preconceptions you may have had about ActionScript and have some interest in playing with it. One of the great things about Flex, Flash, and ActionScript is that they’re available at no cost. Simply download Adobe Flex Builder 3 to get started. Flex Builder, which is a sophisticated integrated development environment (IDE), is not a free application, but the Flex Software Development Kit (SDK) that it uses to build Flash applications is.
A word of warning to language purists out there reading this article: I’m not a language guru, so I might gloss over some language details. I’m also not trying to present everything in ActionScript 3 in this article. If that’s what you’re after, many good books on ActionScript 3 are available. What I can do is give you a feel for the language. Here goes.
Classes and interfaces
Just as with Java, everything is really an object in ActionScript 3. There are a few primitive types like integers, but beyond that everything is an object. Similarly, like Java, there are namespaces and packages, like com.jherrington.animals, which would mean company / jack herrington / animal classes, in this case. You can put classes into the default namespace, but it’s better to control your namespace.
To define a class, you use the class keyword, just as with Java. Here’s an example:
package com.jherrington.animals { public class Animal { public function Animal() { } } }
In this case, I'm defining an Animal
class with a constructor that currently does nothing.
I can add a few member variables and refine the constructor quite easily, as shown here:
package com.jherrington.animals { public class Animal { public var name:String = ""; private var age:int = 0; private function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } } }
Here, I'm defining that an Animal
object has two member variables; name, which is a public string, and age, which is a private integer. (Apparently, animals are shy about their age.) The constructor takes one or two values: either the name alone or the name and an age. You can provide default values for arguments by adding them in the function declaration.
What you notice about this code is that the typing is inverted from Java. In Java, the type comes first; in ActionScript, it comes second. This is because strong typing is an add-on to ActionScript. So to support older, non-typed code, the type comes after the variable name.
Let's extend the example by adding a few methods:
package com.jherrington.animals { import flash.geom.Point; public class Animal { public var name:String = ""; private var age:int = 0; private var location:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } public function moveTo( x:int, y:int ) : void { location.x = x; location.y = y; } public function getLocation( ) : Point { return location; } } }
As you can see here, I've added another private member variable, location
, of type Point
, which I've imported from Flash's geometry package. And I've added two methods that work with the location: moveTo
, which moves the animal, and getLocation
, which returns the current location.
Now, that's kind of the Java way to get and set a value. The ActionScript way to do it is a lot cleaner, as you can see in this code:
package com.jherrington.animals { import flash.geom.Point; public class Animal { public var name:String = ""; private var age:int = 0; private var myLocation:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) { name = _name; age = _age; } public function set location( pt:Point ) : void { myLocation = pt; } public function get location( ) : Point { return myLocation; } } }
Here, I'm using get
and set
functions that are invoked when the client code gets or sets the value of the member variable location
. To the client, the location variable looks just like a regular member variable. But you can set whatever code you like to respond to the member variable setting and handle the get
of the variable, as well.
How can you make use of this? You can add an event that is triggered when the location changes. Check that out in this code:
package com.jherrington.animals { import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Point; public class Animal extends EventDispatcher { public var name:String = ""; private var age:int = 0; private var myLocation:Point = new Point(0,0); public function Animal( _name:String, _age:int = 30 ) name = _name; age = _age; } public function set location ( pt:Point ) : void { myLocation = pt; dispatchEvent( new Event( Event.CHANGE ) ); } public function get location( ) : Point { return myLocation; } } }
Now, I'm specifying that the Animal
class is an event dispatcher
- that is, an object from which clients can listen for events. I then dispatch a new event when the location changes.
Here is the client code that creates an animal, sets itself up to watch for change events, then changes its location:
var a:Animal = new Animal(); a.addEventListener(Event.CHANGE, function( event:Event ) : void { trace( "The animal has moved!" ); } ); a.location = new Point( 10, 20 );
This code brings up a trace message when the animal has moved. You can define any type of messages you want in ActionScript. Most of the classes are EventDispatchers and have events for which you can add listeners.
Interfaces
Just like Java, the ActionScript 3 language supports builder interfaces and implementing them with classes. The interface shown below is an example of what we might make from the Animal
class:
package com.jherrington.animals { import flash.geom.Point; public interface IAnimal { function get name() : String; function set name( n:String ) : void; function get location() : Point; function set location( pt:Point ) : void; } }
In this case, I'm defining two member variables for the interface that I can both set and get. Yes, you can define methods and member variables in ActionScript interfaces. How cool is that?
To implement the interface, I've made some changes to the Animal
class. You can see that in the code below:
package com.jherrington.animals { import flash.events.Event; import flash.events.EventDispatcher; import flash.geom.Point; public class Animal extends EventDispatcher implements IAnimal { private var myName:String = ""; public function get name() : String { return myName; } public function set name( n:String ) : void { myName = n; dispatchEvent( new Event( Event.CHANGE ) ); } private var myLocation:Point = new Point(0,0); public function set location ( pt:Point ) : void { myLocation = pt; dispatchEvent( new Event( Event.CHANGE ) ); } public function get location( ) : Point { return myLocation; } public function Animal( _name:String ) { name = _name; } } }
Of course, I can add variables and methods specific to this class or implement other interfaces in addition to the IAnimal
interface. As with Java, however, I can only inherit from one base class.
Statics and constants
ActionScript 3 supports both constants and static member variables as well as static methods. Constants are easy to define, as you can see in the code below:
public const MINIMUM_AGE:int = 0; public const MAXIMUM_AGE:int = 2000;
Constants can be of any type you like, but they have to be defined at compile time. They can also be protected or private if you want to scope them that way.
To demonstrate a static function, I show a factory method in the Animal
class:
public static function buildAnimal( n:String ) : IAnimal { return new Animal( n ); }
Another way to use static method is in a Singleton pattern. Below is an example of a Singleton factory
class for the Animal
class:
package com.jherrington.animals { public class AnimalFactory { private static var _factory:AnimalFactory = new AnimalFactory(); public static function get instance() : AnimalFactory { return _factory; } public function build( n:String ) : Animal { return new Animal( n ); } } }
To invoke it, I use the instance
member variable to get the single factory
object:
private var b:Animal = AnimalFactory.instance.build( "Russell" );
This uses the Singleton factory object to create a new animal with the name Russell.
Inheritance
To demonstrate inheritance, I show three interfaces and classes. The first interface is the IAnimal
class I showed before. The second is the Animal
class, and the third is a derived class called Dog
that overrides a method.
The interface, IAnimal
, is shown below:
public interface IAnimal { function get name() : String; function set name( n:String ) : void; function move( x:int, y:int ) : void; }
I've simplified it a bit by taking it back to just a name
member variable and a move()
method. The first implementation of the interface is the Animal
class:
public class Animal extends EventDispatcher implements IAnimal { private var myName:String = ""; public function get name() : String { return myName; } public function set name( n:String ) : void { myName = n; dispatchEvent( new Event( Event.CHANGE ) ); } public function Animal( _name:String ) { name = _name; } public virtual function move( x:int, y:int ) : void { } }
Then, the Dog
class builds on the Animal
class by having its own constructor and an override of the move()
method:
public class Dog extends Animal { public function Dog(_name:String) { super(_name); } public override function move( x:int, y:int ) : void { trace( 'Moving to '+x+', '+y ); } }
This is a lot like Java code, so you should feel really at home in implementing your object-oriented designs in ActionScript.
Operators and conditionals
Operators in ActionScript are exactly the same as what you find in Java. Similarly, math and Boolean operators are the same:
var a:int = 5; var b:int = 6; var c:int = a * b; c *= 10; var d:Boolean = ( c > 10 ); var e:int = d ? 10 : 20;
These examples show a few of the different operators. The only difference in these examples between ActionScript and Java is the syntax for defining the variables.
Like operators, conditionals work exactly the same between the two languages-for example:
if ( a > 10 ) { trace( 'low' ); } else if ( a > 20 ) { trace( 'high' ); } else { threw new Exception( "Strange value" ); }
shows both the conditional syntax and how you can throw exceptions. Exception handling is exactly the same in Java. You can define your own exception types or just use the standard Exception class.
The try
, catch
, and finally syntax is shown in the example below:
try { location = new Point( -10, 10 ); } catch( Exception e ) { trace( e.toString() ); } finally { location = null; }
This code tries to set the location and traces out the error if a problem occurs. In any case, the location will be set to null at the end.
Iterators
ActionScript 3 doesn't have strongly typed containers, but it's still easy to work with arrays and hash tables. Here is an example of using a for loop to iterate an array:
var values:Array = new [ 1, 2, 5 ]; for( var i:int = 0; i < values.length; i++ ) trace( values[i] );
But this isn't really the way you want to iterate an array in ActionScript. The best way is to use the for each syntax, as shown in the next sample:
var values:Array = new [ 1, 2, 5 ]; for each ( var i:int in values ) trace( i );
This code iterates through each element in the array and sets the value of i to each element along the way.
To create a hash table, you use the basic Object type in ActionScript:
var params:Object = { first:'Jack', last:'Herrington' }; for( var key:String in params ) trace( key+' = '+params[key] );
ActionScript's origins in JavaScript mean that the base object type is a slots-based container that you can easily use as a hash table.
Regular expressions
Regular expressions are baked right into the base syntax for ActionScript. For example, this code:
if ( name.search( /jack/i ) ) { trace('hello jack'); }
performs a simple check on a string.
This code uses a regular expression to perform a split operation:
var values:String = "1,2,3"; for each( var val:String in values.split(/,/) ) { trace( val ); }
Whether you should have regular expressions embedded in the core syntax is debatable. The architects of Java obviously thought these expressions should go in an external library. But I think that they are useful enough that they should be integrated as they are in ActionScript.
E4X
XML is used widely enough that ActionScript has support for it built right into the language syntax. If you're an XML junkie, you are going to love this. Check it out:
var myData:XML = <names> <name>Jack</name> <name>Oso</name> <name>Sadie</name> </names>; for each ( var name:XML in myData..name ) { trace( name.toString() ); }
This code defines an XML document, then searches it and prints out all the
This next bit of code also gets <name> tags but only
var myData:XML = <names> <name type="person">Jack</name> <name type="dog">Oso</name> <name type="dog">Sadie</name> </names>; for each ( var name:XML in myData..name.(@type='dog') ) { trace( name.toString() ); }
The @
syntax is similar to XPath and XSLT. It's used to specify that we are looking at attributes and not XML elements.
E4X is a fantastic addition to the language. It turns XML parsing from a chore into a delight. Web services can even be returned in E4X format for easy parsing.
Conclusion
Adobe has made some extraordinary strides with ActionScript. It's a far more sophisticated language than most people give it credit for. I think you'll find that what Adobe has done is taken some of the lessons learned from what is right and wrong about Java and incorporated them into their development of the ActionScript 3 language. You'll be very happy with the result.
For more information
- For more on the similarities between ActionScript and Java syntax, read Yakov Fain's article, "Comparing the syntax of Java 5 and ActionScript 3" (JDJ, November 12, 2006).
- A Java-to-ActionScript converter is available for download from Open Source Flash that allows you to use Java rather than ActionScript to create Flash content.
- For a list of resources to help you migrate between ActionScript, Flex, Java, and JavaScript development, see RIAdobe's comparison list.
- Flex.org is your source for all things Adobe Flex.