2

I'm used to a more event driven environment but the copy I'm working at now dose everything as function call backs. When I asked about this one of the devs said it was because callbacks are faster because of bubbling, but the bubbling property could always be set to false...

So I'm having the problem of trying to figure out which callback function is being referenced.

For example:

public class A {
    public function A(){}
    public function func_1():Number{ return 1; }
    public function func_2():Number{ return 2; }
    public function doSomething:Function{ 
        if( Math.random > 0.5 ) return func_1; else return func_2;
    }
}

Then I might run the code in class B:

public class B{
    public var a:A = new A();
    private var action:Function;
    public function B(){ action = a.doSomenthing(); }
}

So when I put a break point inside B I get action = Function (@34567) which is really completely useless... I realize I could put a break point in both func_1 and func_2 but I'm just using this as a general example there are function callbacks sprinkled through out the code... is there a way to get the name of a function by memory address? Thanks

I guess I see what you are saying about the stack trace. But you have to physically step over the function in the code. In this example below I'd have to put a break point on callback(); and step over it to see the stack trace update. The issue is I want to know the callbacks before they are called. Sometimes they are called in other places. There is no other way to get the callback?

public var callbacks:Array = [];
public function loadURL( url:String, callback:Function ){
    loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);
    callbacks.push( callback );
    var request:URLRequest = new URLRequest(url);
    loader.load(request);
}

public function completeHandler( event:Event ):void
{
    for( var i:int = 0; i < callbacks.length; i ++ ){
        var callback:Function = callbacks[i];
        callback();
    }
}
gdoubleod
  • 1,268
  • 3
  • 19
  • 33
  • Look at the call stack from the debugger. – Jason Sturges Jul 28 '11 at 19:22
  • I use callbacks too sometimes, but when I also use asdoc comments, so I've never had any issues before. Also, callbacks might be the only variables of type `Function` in your classes, so it should be easy to identify them. I see your example is using public properties. I'm using protected variables and and getters/setter most of the time. If it helps, you could do something like this: `public function getFunctionVars(instance:*):XMLList{ return describeType(instance).method.(@returnType == "Function"); }` ...but ideally the code you work with should be as simple as possible and documented – George Profenza Jul 28 '11 at 20:07

3 Answers3

2

This is incredibly wonky code, but for the sake of this example you can use the call stack from the debugger:

enter image description here

Your example code had many issues, but this capture is based upon minor tweaks to your implementation:

package
{
    import flash.display.Sprite;

    public class MultiCallback extends Sprite
    {
        public function MultiCallback()
        {
            super();

            var b:B = new B();
            b.action()();
        }
    }
}


internal class A
{
    public function A()
    {
    }

    public function func_1():Number
    {
        return 1;
    }

    public function func_2():Number
    {
        return 2;
    }

    public function doSomething():Function
    {
        if (Math.random() > 0.5)
            return func_1;
        else
            return func_2;
    }
}

internal class B
{
    public var a:A = new A();

    public var action:Function;

    public function B()
    {
        action = a.doSomething;
    }
}
Jason Sturges
  • 15,855
  • 14
  • 59
  • 80
2

You can throw an error inside a try...catch so that you can inspect the stack without killing the application. This solution makes me cringe, but at the same time it's quite cunning. Originally by Ralf Bokelberk, but since his blog currently doesn't work I'll link to here instead, which is where I found it.

And here is the technique in code for posterity:

var stackTrace:String;

try { throw new Error(); }
catch ( e: Error ) { stackTrace = e.getStackTrace(); }

var lines:Array = stackTrace.split('\n');
var isDebug Boolean = (lines[int(1)] as String).indexOf('[') != int(-1);

var path:String;
var line:int = -1;

if (isDebug) {
    var regex:RegExp = /at\x20(.+?)\[(.+?)\]/i;
    var matches:Array = regex.exec(lines[int(2)]);

    path = matches[int(1)];

    //file:line = matches[2]
    line = matches[int(2)].split(':')[int(2)];//windows == 2 because of drive:\
} else {
    path = (lines[int(2)] as String).substring(4);
}
shanethehat
  • 15,460
  • 11
  • 57
  • 87
1

Man i am in the same boat. This code base is huge and done in the same way. "Sprinkled" would be an understatement in my case. If a function object has no function name handler, you are SOL. One of the ways for me to comprehend my way through the code was to use UML to represent this different classes and use the association operator to show this is calling something. It's so easy to get lost when callbacks are calling back another callback. Having a UML Diagram that you make is like bread crumbs trying to get yourself out of the rabbit hole. After a while, you get used to it. Would I adopt this way of programming? Hells no, they just made it harder for the next guy to maintain. I use Violet UML to track my journey through the callbacks.

Mark Lapasa
  • 1,644
  • 4
  • 19
  • 37