June 22, 2004

ActionScript scoping

I recently ran into this crazy ActionScript scoping issue, that drove me so crazy I decided it needed a post. ActionScript is an ECMAScript language so learning it has been very fun. I'm able to use all my JS knowledge and then extend it to a much richer language.

In my test app, I've got a button, fTestButton, and a text field, fConsole.

If I have this in the actions panel:

fTestButton.onRelease = function() {
    trace("Button clicked, this = " + this + " and console = " + fConsole);
}
then when I click the button, I get:
Button clicked, this = _level0.fTestButton and console = _level0.fConsole

As best I can tell what's happening is that fConsole's scope is being evaluated at the time the function is created. This seems reasonable and consistent with everything I've read about ActionScript up until this point.

But if I then put this in an external class file, like this:

class Test {
    var mConsole;
    Test(t:MovieClip) {
        mConsole = t.fConsole;
        trace("console = " + mConsole);
        t.fTestButton.onRelease = function() {
          trace("Button clicked, this = " + this + " and console = " + mConsole);
        }
    }
}
and create it on the stage with
var foo = new Test(this);
Then my output is:
console = _level0.fConsole
Button clicked, this = _level0.fTestButton and console = undefined
The problem this exposes is that only the value of local variables is actually resolved in the event handler, or in any anonymous function declaration. Members of the containing class are not accessible.

The solution is make any member variables accessible within the current function's scope so that when the event handler is declared, it resolves these values appropriately.

Here's the fixed class:

class Test {
    var mConsole;
    Test(t:MovieClip) {
        mConsole = t.fConsole;
 
        // now store a local copy of this variable
        var console = mConsole;
 
        trace("console = " + mConsole);
        t.fTestButton.onRelease = function() {
          // reference the local console variable, rather than the member variable
          trace("Button clicked, this = " + this + " and console = " + console);
        }
    }
}

This unfortunately leads to some somewhat hacky code, if your event handlers need to access many internal methods or calls. One solution to this is just to declare a local reference to 'this' and throw it around inside your event handler.

Here's another approach, using a local reference to 'this':

class Test {
    var mConsole;
    Test(t:MovieClip) {
        mConsole = t.fConsole;
 
        // now store a local reference to 'this'
        var thisTest = mConsole;
 
        trace("console = " + mConsole);
        t.fTestButton.onRelease = function() {
          // reference the console through 'thisTest'
          trace("Button clicked, this = " + this + " and console = " + thisTest.mConsole);
        }
    }
}

Both ways work. The former leads to simpler code if you just need to access one variable within your anonymous function, but the latter is useful if you need access to many members, or need to call methods on 'this'

Word has it Macromedia is releasing some kind of helper class to make this easier, but it is disappointing to me that ActionScript couldn't be slightly more consistent about the way it resolves values inside of anonymous functions.

Posted by alecf at 11:35 AM | Comments (1) | TrackBack

June 14, 2004

I'm famous!

A long time ago, people were bitching about Hungarian notation in code. Its a rediculous convention perpetrated by Microsoft in the early nineties. During some debates on a mozilla newsgroup, circa 1999, I made this comment:

prepBut nI vrbLike adjHungarian! qWhat's artThe adjBig nProblem?

Well, I had no idea how this goofy statement had been passed around. A quick search on google turns up all sorts of hits where people have used it in their e-mail signature. I even found a guy offering T-shirts with the quote.

Anyhow, I just found the whole thing funny.

Posted by alecf at 04:34 PM | Comments (0) | TrackBack

June 09, 2004

OpenJade and Cygwin

I've spent more time with OpenSP/OpenJade trying to get everything working under Cygwin, and I think I've finally got it.

Here's what I had to change:
  • OpenSP 1.5.1
    1. Edit config.h.in, and comment out #define SP_HAVE_LOCALE OpenSP will work with this turned on, but OpenJade will break. Better to just disable locale support in OpenSP and let OpenJade figure it out later.
    2. Run configure --with-included-gettext Cygwin's gettext support is lacking bindtextdomain or something.
    3. Ditch the #pragmas Cygwin doesn't support #pragma interface and #pragma implementation, and it results in undefined symbols during linking. This is in a lot of the source files, you'll probably want to write a perl or awk script to take care of it.
  • OpenJade 1.3.2
    1. Edit grove/Node.h, and change the #ifdef SP_WCHAR_T_USHORT to #ifdef SP_WCHAR_T_USHORT_ OpenJade defines it's Char type as a Unsigned32. This is apparently incompatible with grove's definition of GroveChar as a wchar_t. Cant' we all just get along?
    2. Edit msggen.pl, and add a second chop; - gotta love window's CRLF linefeed sequence, and the way it confuses perl.

At this point, I know I can run the openjade.exe binary. I haven't really fiddled with it any more, but I have an article I want to format as HTML.. so that's next.

Posted by alecf at 10:49 AM | Comments (5) | TrackBack