July 30, 2006

Flex 2 Runtime Error 1009 and Runtime Modules

While the following error is most often encountered when trying to access a property or function through a null object reference, it can also rear its head when working with runtime modules.

TypeError: Error #1009: Cannot access a property or method of a null object reference.
	at mx.containers::Panel/mx.containers:Panel::layoutChrome()
	at mx.core::Container/mx.core:Container::updateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\Container.as:2910]
	at mx.containers::Panel/mx.containers:Panel::updateDisplayList()
	at mx.core::UIComponent/validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:5672]
	at mx.core::Container/validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\core\Container.as:2731]
	at mx.managers::LayoutManager/mx.managers:LayoutManager::validateDisplayList()[C:\dev\GMC\sdk\frameworks\mx\managers\LayoutManager.as:594]
	at mx.managers::LayoutManager/mx.managers:LayoutManager::doPhasedInstantiation()[C:\dev\GMC\sdk\frameworks\mx\managers\LayoutManager.as:646]
	at Function/http://adobe.com/AS3/2006/builtin::apply()
	at mx.core::UIComponent/mx.core:UIComponent::callLaterDispatcher2()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:7789]
	at mx.core::UIComponent/mx.core:UIComponent::callLaterDispatcher()[C:\dev\GMC\sdk\frameworks\mx\core\UIComponent.as:7732]

The problem seems to be that if the runtime module makes a side-effect reference to a component, which is not included in the main application, it never really gets included in the SWF and as such causes problems when accessed. That's a jumble of words so I think an example is needed.

Create a Flex Application with two files in it. The first one is called com.example.PanelComp.mxml:

<?xml version="1.0" encoding="utf-8"?>
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" width="400" height="300">
    <mx:Text text="Hi"/>
</mx:Panel>

The second one is the main application, call it LoadTest.as:

package {
    import com.example.PanelComp;
    import mx.core.SimpleApplication;

    public class LoadTest extends SimpleApplication {
        private static var panelComp:PanelComp;
    }
}

For more information on that SimpleApplication business check out Roger Gonzalez's blog.

Now in a different Flex Application we want to load the first application and then create an instance of PanelComp.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical">
    <mx:Script>
        <![CDATA[
            import mx.containers.Panel;
            import flash.utils.getDefinitionByName;

            // must uncomment for "Add Panel" to work
            // TypeError: Error #1009:
            // private static const panel:Panel = null;

            private var _loader:Loader;

            private function loadSwf(location:String):void {
                _loader = new Loader();
                var ctx:LoaderContext = new LoaderContext();
            	ctx.applicationDomain = ApplicationDomain.currentDomain;
            	_loader.contentLoaderInfo.addEventListener(Event.INIT, swfInit);
                _loader.load(new URLRequest(location), ctx);
            }

            private function swfInit(e:Event):void {
                _loader.content.addEventListener("ready", swfLoaded);
            }

            private function swfLoaded(e:Event):void {
                trace("Loaded");
            }

            private function createPanel():void {
                var clazz:Class = Class(getDefinitionByName("com.example.PanelComp"));
                // see note above about TypeError: Error #1009:
                addChild(new clazz());
            }
        ]]>
    </mx:Script>
    <mx:Button label="Load" click="loadSwf('../../LoadTest/bin/LoadTest.swf');"/>
    <mx:Button label="Add Panel" click="createPanel();"/>
</mx:Application>

As noted in the comments, until you uncomment the static reference to Panel in the wrapper application, you will get the stack trace. Something to keep in mind if you are using runtime modules.

Tags: actionscript as3 flex programming

July 30, 2006

Flex 2 Runtime Error 1065

Today while working on some code I started getting this error and stack trace:

ReferenceError: Error #1065: Variable LoadTest is not defined.
	at global/flash.utils::getDefinitionByName()
        at ... (rest of stack trace deleted)

Looking the error up in the documentation didn't help point the way to what might be going on since this had nothing to do with a "variable":

1065 Variable _ is not defined. You are using an undefined lexical reference. For example, in the following statements, the statement trace(x) generates an error because x is undefined. However, the statement trace(y) doesn't generate an error because y is defined: trace("hello world") trace(x) // x is undefined var y trace(y) // No error, y is defined.

In this case I was trying to dynamically instantiate a class by first finding the definition of that class and then newing it. Something like this:

public function createInstance(className:String):Object {
    var instance:Class = Class(getDefinitionByName(className));
    new instance();
}

It turns out the reason why the error was being thrown was that in my Flex Application I didn't have anything which "used" the class. In other words the compiler thought that the class was left over junk and didn't include it in the compiled swf. By adding in a use of it, everything started working. As example use would be something like:

private static const loadTestRef:LoadTest = null;

If there is another way to get this same behavior, please let me know.

Tags: actionscript as3 flex programming

June 30, 2006

Dynamic Interface

I would like a way in AS3 to define an interface as being dynamic. In some cases I want all classes that implement an interface to also have to be dynamic. Why might this be useful? I find the chained property accessors much nicer to deal with. I'm not as concerned about adding new methods to the interface and some of the other stuff that you can do with a dynamic class, I just want easy access to unspecified attributes. The fact that you can still use the associative array style lookup on an interface to get the same result only strengthens my belief that you should be able to mark an interface as dynamic.

Since you can't apply the dynamic keyword to an interface and there doesn't seem to be a system interface that endows dynamicness on an interface, you are forced to either use looser typing or use the alternative syntax. I think this calls for an example.

Say I have this interface defined:


package com.example {
public interface ISample {}
}

In another class I have a method that uses that interface:


package com.example {
public class UseSample {
public function displayProp(sample:ISample):void {
trace(sample.prop);
}
}
}

That generates the lovely compiler error:
1119: Access of possibly undefined property prop through a reference with static type com.example:ISample.

If you change the code to use array syntax it will compile:


package com.example {
public class UseSample {
public function displayProp(sample:ISample):void {
trace(sample["prop"]);
}
}
}

In my mind the array syntax is much more obtuse. Oh well, I can always hope :)

Tags: actionscript as3 flex programming

June 30, 2006

Interface Constants

Since it has come up a couple of times these past two days, I'm a little disappointed that AS3 interfaces don't support constants. I guess I'm too used to Java's interfaces and really wish AS3 interfaces were as versatile. I've ended up using a class which just has static constants in it to simulate the constants that I would normally have applied to the interface.

If I'm missing some syntax or a better way around this issue, please let me know.

Tags: actionscript as3 flex interfaces

June 30, 2006

Regular Expressions

I've been playing around with Flex 2 for some time at work. One of the neat things that Actionscript 3 adds is native regular expressions. As part of an ongoing effort to share knowledge I volunteered to give an informal talk about regular expressions. To help with the talk I created this visual regular expression viewer. It helps show you what matched along with any groupings and other standard stuff. Additionally it can also perform a regular expression replace operation or a simple split operation.

You will need the Flash 9 in order to run the application.

Launch RegExp Tester!

If you find any bugs, have comments, etc. please leave me a comment.

Tags: actionscript as3 programming regexp regularexpression

May 31, 2006

Flex Beta 3

For anyone following Flex, beta 3 is now available.
From my experience, Flex Builder is much improved but there are still many quirks with it. There were quite a few Actionscript 3 language changes, but the documentation on them is good. My biggest complaint so far is that many MXML files in a Flex library project are not being handled properly by the MXML Editor which results in a complete lack of code assist. The same MXML file in a Flex Application works fine. I've not completely figured out why some of the files are so broken, especially when they seem to work fine on another user's system.

Tags: actionscript as3 flex programming

April 30, 2006

Actionscript 3 Class.forName

I'm sure this would be obvious for anyone that has been programming in Actionscript 3 for awhile, but coming in from the Java world I'm still trying to find the matching idioms. In particular I wanted a way to dynamically load a class based on its name. In Java this is the Class.forName() construct. Luckily AS3 also has a similar mechanism:

// return the class as a Class object
var temp:Class = flash.utils.getDefinitionByName("com.example.Sample") as Class;
// you can now call new it to create an instance along with passing constructor args
var instance:Object = new temp(arg1, arg2, ...);

If when doing this you get an "Runtime Error 1065" see this post.

Note: Update Nov 6, 2007
It looks like flash.util.getClassByName() has gone away. The example above has been updated to use the new mechanism called flash.utils.getDefinitionByName().

Tags: actionscript as3 programming

April 30, 2006

Actionscript 3 FAQ

Mike Chambers is asking for input on improving the Actionscript 3 FAQ.

Tags: actionscript as3 faq programming

April 30, 2006

Private or Helper Classes in Actionscript 3

I didn't find this well documented when I was looking it up so I thought I'd post a sample. While Actionscript 3 (AS3) doesn't support protected and private classes like Java does, you can have helper classes that are only visible within the file that they are defined. The syntax for them is a little weird but the Flex 2 Beta 2 compiler seems to like it. The syntax is that after the package you define the helper class:

package com.example {
     public class Sample {
          private var _helperClass:HelperClass = new HelperClass();
     }
}
// imports for the helper class go here
import com.example.xml.SaxHandler;
class HelperClass {
     private var _saxHandler:SaxHandler;
}

Tags: actionscript as3 programming

April 30, 2006

Flex 2, Actionscript 3, and E4X

I've found a feature of Actionscript 3 (AS3) that I've not seen in other languages that I think is pretty cool. It's taken me awhile to come to terms with it, but now that I've getting more comfortable with it I'm really starting to appreciate it. That feature is what is known as E4X or more officially Standard ECMA-357 ECMAScript for XML (E4X) Specification. At its core is the ability to work with and manipulate XML data in AS3 using standard language syntax instead of having to do everything through an API.

For example to create a variable that contains some hard coded XML you could just write:


var xml:XML =
<componentPackage>
<component id="MyButton" class="package1.MyButton"/>
<component id="MyOtherButton" class="package2.MyOtherButton"/>
</componentPackage>;

Notice the lack of any "new XML("")" or other traditional methods one might use to create an XML document. Pretty cool stuff. You can also do variable substitution when creating XML:


var attributeName:String = "class";
var xml:XML =
<componentPackage>
<component id="MyButton" {attributeName}="package1.MyButton"/>
<component id="MyOtherButton" {attributeName}="package2.MyOtherButton"/>
</componentPackage>;

That creates an XML document that looks exactly like the first XML example. Not the most convincing example, but you get the idea. You can substitute element names, attribute names, or whole attribute values. Besides being able to do inline XML document creation you can also do DOM style navigation to get at elements and attributes within the XML (these return XML or XMLList objects). Going back to the first XML example:


xml.component[0]; // <component id="MyButton" class="com.example.ui.MyButton"/>
xml.component[0].@id; // MyButton

Where things get really cool is the XPath like operations, technically called filters since it isn't as expressive as XPath:


xml.component.(@id == "MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>

That searches for all component elements under the root that have an id of MyButton. There are a bunch more. In fact the Working with XML (doc link subject to change) section of the Flex 2 documentation has many good examples. It's at this point that I want to offer a hard learned lesson about what doesn't work with E4X (at present anyway, I can only hope that it will be solved in a future Flex 2 release).

The following line of code doesn't compile (again using the first XML example from above):


xml.component[0].@class; // Error: Expecting identifier before class

The reason is that "class" is a reserved keyword. Thankfully E4X provides alternative attribute access syntax, an example is:


xml.component[0].@["class"]; // package1.MyButton

A little clunky, but still reasonable. What I haven't been able to get working is any of the alternative syntaxes when trying to do a filter using the same attribute:


xml.component[0].(@class == "package1.MyButton"); // Error: Expecting identifier before class

I've tried all four listed variations: element.@attrName, element.attribute("attrName"), element["@attrName"], and element.@["attrName"]. None of them work in the above example, adjusted of course to account for the () filtering operation. This afternoon I finally stumbled upon a solution. This is even more clunky then the alternative attribute accessors, but it does eliminate the need to write custom loops to handle filters like the one above:


xml.component.(@\u0063lass == "package1.MyButton"); // <component id="MyButton" class="com.example.ui.MyButton"/>

In this case I'm using the Unicode value for the letter c (0063) which to my surprise worked. As I said earlier I hope this keyword issue is just a beta issue and it will be resolved. If not, consider using this approach to construct E4X filters that might reference AS3 keywords.

Tags: actionscript as3 e4x flex programmin xml