Properties, dynamic behavior, and functions in ActionScript 3 Like a lot of newer languages, ActionScript 3 is different from Java when it comes to properties, dynamic behavior, and some very convenient aspects of functional programming. In this second half of his Java developer’s guide to ActionScript 3, Chet Haase uses side-by-side code samples to demonstrate the differences in syntax and behavior. He also talks about capabilities and usage patterns that could come as a surprise, if you’re viewing ActionScript through Java-tinted glasses. Level: IntermediateI hope you got a chance to read the first half of this article, which introduced the topic of ActionScript 3 from a Java developer’s perspective. In that article I gave an overview of ActionScript 3 and how it fits into the Flash platform and Flex development, and then looked at some of the differences in syntax and class structure between the two languages. If you’re new to Flex development or ActionScript, Part 1 is good background for what you’ll learn here. If you didn’t get a chance to read it yet, you might want to do so now.Go ahead, I’ll wait. Okay, ready? Then let’s get started.In this installment, I’ll introduce some of the areas where we begin to see a striking, and more conceptual, difference between programming in Java versus ActionScript 3 (AS3, from now on) namely:Properties: Some of the more interesting differences between Java and AS3 involve how properties are declared and used.Dynamic behavior: Scripting languages are known for their dynamic behavior, or the ability to change classes, functions, and structures on the fly. AS3 is no stranger to this feature, and I’ll show you how it fits into the language.Functions: Java calls them methods, ActionScript calls them functions, but they’re functionally equivalent. Still, there are some important differences to be discovered.A proper tease on propertiesHow properties are declared and used is one of the biggest differences between Java and ActionScript. In this section, you’ll see how properties differ between the two languages at the API level, and how that changes the way they are declared and used. Fields versus propertiesJava has fields in classes, which can be public and directly settable/gettable: public class JavaProps { public int blah; } JavaProps props = new JavaProps(); props.blah = 5; Good Java coding practice uses optional JavaBeans conventions for getting and setting fields, which are then declared as private:public class JavaProps { public int blah; private int foo; public void setFoo(int value) { foo = value; } public int getFoo() { return foo; } } JavaProps props = new JavaProps(); props.blah = 5; props.setFoo(5); AS3 has properties as a first-class citizen of the language. In particular, there are get and set keywords that define special getters/setters for properties. For example, you could have either public class AS3Props { public var foo:int; } orpublic class AS3Props { private var _foo:int; public function set foo(value:int):void { _foo = value; } public function get foo():int { return _foo; } } In either case, callers would access the property using standard “field” access: AS3Props props = new AS3Props(); props.foo = 5; trace("foo = " + foo); // outputs '5' This equivalence in AS3 between fields and get/set functions has some interesting and profound implications, especially for developers writing APIs. (That explains my particular interest in this subject, by the way: I work on the Flex SDK team developing the Flex APIs.) For example, changes between the two representations have no impact on the public API since the calling mechanism for both is the same. As a result, you can evolve your API over time between the two options without causing problems for your users. Let’s see how this works in an example.The future-proof APISuppose you had some field foo that you exposed as a public field in Java (it’s really such a simple thing that you didn’t want to go to the trouble of writing the setter/getter functions): public class JavaProps { public int foo; } Your users get used to calling the field directly, like so: JavaProps props = new JavaProps(); props.foo = 5; Then one day, for tracking purposes or some other nefarious reason, you decide that you want to know how many times a user sets that field. It’s a simple change to use a getter/setter for the field instead:public class JavaProps { private int foo; public void setFoo(int value) { this.foo = foo; } public int getFoo() { return foo; } } But your users don’t take kindly to this change because their old, familiar code now breaks. They have to change their source code and recompile if they want to use this wonderful new version of your library: JavaProps props = new JavaProps(); props.foo = 5; // runtime error on previously compiled code // also, compiler error if you try to build it against new library Moreover, users must write new code to adhere to the new calling convention: props.setFoo(5); This painful approach to upgrading property APIs in Java means that either the APIs are not changed at all, leaving some parts of the library stale or obsolete, or users of the libraries are forced to change their code to compensate, which can lead to consternation and grumbling all around.Meanwhile, the AS3 library developer could make the change from field to set/get functions without ever breaking the user code, either the previously-compiled version or any new versions that they compiled against the new library. Their old code would simply work:var props:AS3Props = new AS3Props(); props.foo = 5; This flexibility is a nice way to future-proof your property-related APIs. Note that fields cannot be overridden in AS3. While you can evolve your API over time if necessary, it is still a good convention in AS3 to use get/set functions to begin with. Doing so is insurance in case you or developers using your library ever want to vary the behavior of setting or getting the property value in subclasses.Property access via stringsIn Java, fields are always accessed through the name of the field:public class JavaProps { public int foo; } JavaProps props = new JavaProps(); props.foo = 5; Property access in AS3 is similar, as you saw previously, whether the property is a field or available through get/set functions. But AS3 also allows access to the variable through a string representing the name of the property: public class AS3Props { public var foo:int; } var props:AS3Props = new AS3Props(); // all of the following are equivalent props.foo = 5; props["foo"] = 5; var propName:String = "foo"; props[propName] = 5; This usage in AS3 has some interesting implications and usage patterns. For example, I use this feature in some animation classes that I am writing for animating properties on arbitrary objects in Flex. The animation API is declared very generically to take targets of type Object and the classes do not know at compile time what the properties are that will be animated. But the caller can tell the class instances what properties to animate by passing in strings for the property names, like “x” and “y”. Then, at runtime, the class can combine the target object of the animation (target) with the name of the property (propName) and set the property to the new animated value (value) like this:target[propName] = value; Untyped property accessThis item is related to the previous one where you saw different ways of accessing fields on an object. In Java, you always access fields directly as variables of an instance. This means that if the field does not exist on the instance, you will get a compiler error because you are trying to access something that just is not there:public class FooType{} FooType foo = new FooType(); foo.x = 5; // compiler error because x not in FooType AS3 has similar behavior for typed classes: public class FooType {} var foo:Footype = new FooType(); foo.x = 5; // compiler error because x not in FooType If you try to access the property through the String accessor, you can skate by the compiler but will be thwarted later with a runtime error:foo["x"] = 5; // no compiler error, but you will get a runtime error Enter dynamic objectsI like to think of AS3 as a “mostly type-safe language.” This probably has no real meaning when talking about programming languages, and I’d have my coding fingers whacked with a thick language textbook for using such terminology in the wrong crowd. But bear with me as we investigate AS3’s ability to refer to properties that may not be defined on an object.As demonstrated above in the FooType example, you can treat AS3 as a type-safe language and access fields in AS3 just like you do in Java and you’ll get similar compiler errors when your types and properties do not match. But it’s also possible to game the system if you want to do something different. For example, if you have an Object or an “untyped” reference, or if you declare a class as “dynamic,” then you can avoid compiler and runtime errors when accessing unknown properties: public dynamic class FooType {} var foo:Footype = new FooType(); var blah:Object = new Object(); var flarg:* = new Object(); foo.x = 5; blah.x = 5; flarg.x = 5; // no compiler or runtime errors At first glance, this doesn’t make sense; you’re accessing a property that obviously isn’t on any of the classes for the references you’ve created, yet there are no errors at either compile-time or runtime. So what’s happening?This is a first glimpse into dynamic objects, where AS3 objects can act like maps. Even though the property x does not exist on any of these objects, you are making it exist. You are adding the property named x as a key to each of these instances and associating the value 5 with that key. There are no complaints from the compiler because all three of these objects are recognized as being dynamic, and thus can have properties added to them at runtime. And there is no runtime error because you’re not doing anything illegal; you’re just adding a new member to the objects.You’ll learn more about dynamic behavior in the section that begins after this next word. Dynamic behaviorAn aspect of AS3 that is unusual for anyone coming from a Java programming background is AS3’s “dynamic behavior,” which I define here as the ability to add new capabilities (functions and properties) to existing objects. You’ve seen how dynamic behavior applies to properties in AS3, but that’s just the beginning. In this section, I’ll show how dynamic behavior applies to maps, arrays, and untyped variables in AS3.MapsI mentioned earlier that AS3 objects can act like maps. That’s a topic worth delving further into because it’s very different from the way things are done in Java. In Java, there are maps, but that functionality exists in the library, not the language itself. For example, here’s everyone’s favorite HashMap class:HashMap map = new HashMap(); map.put("foo", 5); Object blah = new Object(); map.put(blah, 14.0); In AS3, every Object is automatically a String map: var map:Object = new Object(); map["foo"] = 5; But note that these maps can only store String keys. For Object maps, AS3 uses the Dictionary class:var map:Dictionary = new Dictionary(); var blah:Object = new Object(); map[blah] = 14.0; And, as I noted before, this String map behavior is not limited to Object; it can also be used on untyped objects or instances of classes declared with the dynamic keyword.Array … of hopeRelated to what I’ve said about stuffing arbitrary properties onto AS3 objects, AS3 arrays are more dynamic than Java arrays. In Java, arrays are declared with a set size, and each operation on array elements will cause a check on the array bounds:Array myArray = new Array(1); myArray[0] = new Object(); myArray[1] = new Object(); // throws really long ArrayIndexOutOfBoundsException AS3 arrays are more flexible. You do not declare an array with a set dimension, and the array is expanded as necessary to fit new elements: var myArray:Array = []; myArray[0] = new Object(); myArray[1] = new Object(); // no error, array expands to fit new items Behind the curtain, arrays are essentially like the maps I discussed before, but with integer access keys.Untyped variablesI said before that I think of AS3 as being “mostly type safe.” Its ability to have references that have no type at all is a big part of that. In Java, there is always a type associated with a variable:Object foo; bar; // Compiler error on bar declaration; makes no sense AS3, on the other hand, allows references to be “void typed”, either by explicitly declaring them as such with the * type, or by implicitly doing so with no type declaration whatsoever:var bar; var blah:*; // bar and blah will both be void-typed Initializing dynamic propertiesJava initializes the values of instance variables either through the construction process or afterwards through individual field assignments (or other, more indirect means):public class FooObject { int blah; } FooObject foo = new FooObject(); foo.blah = 5; AS3 has similar mechanism to Java’s, but also allows JSON-like syntax to express object values literally when creating instances of type Object:var foo:Object = { blah:5 }; Note that this example both creates and initializes the object, as opposed to the separate steps in the Java example above; the JSON syntax will implicitly instantiate an object and populate it with the specified values.Function versus formJava calls them methods, AS3 calls them functions. They’re really the same thing, but there are some interesting differences in how functions work in AS3 compared to methods in Java.Functions as objectsIn Java, methods are simply members of classes, like fields:package foo; public class MyClass { public void blah() {} } In AS3 functions are actually objects. In fact, Function extends Object. And, although they are found mostly at the class level, they can also exist at the package level:package foo { public function bar():void {} } package foo { public class MyClass { public function blah():void {} } } (Note that, like Java, Flex allows only one public class or function to be declared in any single file.)Also, AS3 has the concept of anonymous functions, or functions that can be declared inline:var f:Function = function():void {}; f(); This feature can be useful for declaring callbacks or event handlers inline, as an example.Function passingIn Java, methods are usually called through their owning class or instance. It is possible, with reflection, to call methods through references, but there is no concept of “function pointers.”In AS3, because functions are Objects, they can be passed around willy-nilly, just like any other object:public class Foo { public static function blah():void {} } bar.blahRef = Foo.blah; bar.blahRef(); public function groob(func:Function):void { func(); } var groobRef:Function = groob; groobRef(Foo.blah); Notice, in the above code, that it’s possible to use references to either static or instance functions, and that you can then call through those references directly. It’s like C’s function pointers without all those pesky *s and &s flying around.Overriding … passionIn Java, method overriding is automatic. As long as a subclass declares a method with the same signature as a method in one of its superclasses, it will automatically override that superclass method.In AS3, the override keyword is required and a compiler error will be thrown if the subclass declares a function with the same name without explicitly declaring that it is an override:public class Foo { // extends Object <b>override</b> public function toString():String {} } Function overloadingIn Java, method overloading is common. You can have several methods with the same name as long as they differ in the number or types of parameters: public void foo(int x) {} public void foo(int x, Object y) {} foo(5); foo(5, new Object(); In AS3 (as in Highlander) there can be only one: public function foo(x:int):void {} public function foo(x:int, y:Object):void {} // compiler error One workaround for function overloading in AS3 is to use AS3’s default-value feature for input parameters. Conveniently, that’s our next topic.Default parameter valuesDefault parameter values is a feature that is available in AS3 but not in Java. In Java, the parameters declared for any method are exactly those expected from the caller (with the exception of the varargs feature of both Java and AS3, which allows an arbitrary number of values to be passed in). In AS3, it is possible to declare default values for each parameter that are used if that parameter is not actually passed into the function. For example, you could achieve a similar effect to the previous Java overloading example by making the second argument of the single AS3 function optional:public function foo(x:int, y:Object = null):void {} foo(5); foo(5, new Object()); The default-value workaround only works in cases where it’s possible to arrange parameter order and values appropriately, but it is at least sufficient for these simple cases.return;In this two-part article I’ve attempted to provide a glimmer of what ActionScript looks like when seen through Java-tinted glasses. Rather than try to describe the complete spectrum of differences between the languages, I’ve preferred to leave you with an overall taste of AS3. In particular, I hope you’ve gained a sense of how similar AS3 is to Java in many respects. This article also acts as a guide to key places where the languages differ, and how those differences lead to different capabilities and usage patterns.A couple of years ago, I traveled around Germany for a few days. I didn’t know the language at all, but I learned enough about pronouncing numbers in German that I could confidently walk into any bakery and, through a combination of saying the numbers correctly, pointing, and grunting, I could get what I wanted. Of course, there was usually a follow-up conversation when someone assumed that I spoke German (probably due my German ancestry and my awesome pronunciation of “Zwei!“) I didn’t even know enough to say “I have no idea what you’re talking about.” But this awkwardness was usually resolved by my saying, in my best slow American English, “Uh …” upon which the native German would take pity on me and give me my pastries.Every language has its uses and advantages, and successful programming comes from understanding the strengths and constraints of a language well enough to exploit and work around both. Really, language is just a tool for expressing the underlying concepts and logic necessary to get what you want. Or, to put it differently, as long as you understand a language well enough to walk away with two pastries, then life is good.AcknowledgementsThanks to James Ward of Adobe for helping with the original presentation that these articles are based upon. Thanks also to Jeff Dyer, an actual language expert at Adobe, for providing a timely technical review and ensuring that I wasn’t simply rattling off a bunch of half-baked opinions and outright stinking lies.Chet Haase is a senior computer scientist on the Flex SDK team at Adobe Systems, where he spends most of his time working on animation and graphics-related technologies. He is the co-author of the Java book Filthy Rich Clients about graphics effects programming and the author of the humor book When I am King…, which has nothing whatsoever to do with Java, graphics, ActionScript, programming, or anything else. JavaSoftware Development