Here's the simplest test case I can construct (doesn't even need the debugger :)

<canvas>
<attribute name="laszloAttribute" value='function (n1, n2) { output.addText(output.formatToString("%s: %d - %d\n", arguments.callee, n1, n2)); return 0}' />

  <method name="laszloMethod" args="n1, n2">
output.addText(output.formatToString("%s: %d - %d\n", arguments.callee, n1, n2)); return 0;
  </method>

  <text name="output" multiline="true" />

  <handler name="oninit">
      var arr = [ 1,2,3 ];

      output.addText('-- Laszlo Method --------\n');
      arr.sort( canvas.laszloMethod );

      output.addText('-- Laszlo Attribute -----\n');
      arr.sort( canvas.laszloAttribute );
  </handler>
</canvas>

Which makes me wonder if LzText#format should append by default, rather than clobbering the existing text?

On 2008-01-09, at 17:37 EST, P T Withington wrote:

yes please.

Simple test case is to compare the behaviour of the attribute and method declarations.

It's a swf-only bug.

On 2008-01-09, at 17:34 EST, André Bargull wrote:

Should we create a JIRA-entry for this bug, so either to create a fix (somehow), or to document it at least.

- André

On 1/9/2008 11:07 PM, P T Withington wrote:
I take back my explanation regarding `this`.

What it really is is a bug in the Flash implementation of "function scope". When you define a function, it is supposed to capture the scope that it was defined in (and use that scope to look up free references in). The Flash player makes a optimization of never capturing the scope of a function defined in the global scope. This would be fine, because you call all your functions in the global scope, so it will be there when you call.

BUT, Henry is right (as usual).

There are a bunch of places in the player where as functions are being called by player internals (surely C or C++), and the player "forgets" to call the function in the global scope. The most common place we run into this is in the idle loop. But apparently the Array#sort method is another case. We used to have to write all our code that would be used in the idle loop to explicitly reference everything from `_root` (which must somehow be specially looked up, not just looked up in the scope chain).

A while back, we worked around this issue by making sure that every method we define is defined in such a way as to trick the runtime into capturing the global scope on the function. It seems like that technique is not working 100%.

And it seems that when a free reference is made from a function and the scope chain is empty, the function just immediately exits, which is why you see no output.

The (apparent) reason that tracing or closing over the function works is that both are invoking the scope-less function inside a function that _does_ have a scope, so it all works out.

So, really, this is a bug in our compiler's work-around for the scope issue. If you rewrite the canvas method as:

<attribute name="laszloMethod" value='function (n1, n2) { Debug.write("%s: %d - %d (%s)", arguments.callee, n1, n2, Debug); return 0}' />

(which should be equivalent), everything works...

On 2008-01-09, at 16:13 EST, André Bargull wrote:

Another riddle for Tucker:

I can call:
_root.Debug.write("%s: %d - %d", arguments.callee, n1, n2);

But I cannot call:
_root.Debug.write("%s: %d - %d (%s)", arguments.callee, n1, n2, Debug);//or i.e. global, canvas etc. breaks, too

So, in which context does get Array#sort(..) called?

It _is_ getting called. For some reason, your Debug.write is failing to send any output:

lzx> Debug.trace(canvas, 'laszloMethod')
lzx> [1,2,3].sort(canvas.laszloMethod)
TRACE: [394491.00] laszloMethod.apply(?undefined?, [1, 2])
laszloMethod( 1 , 2 )
TRACE: [394501.00] laszloMethod -> 0
TRACE: [394505.00] laszloMethod.apply(?undefined?, [1, 3])
laszloMethod( 1 , 3 )
TRACE: [394512.00] laszloMethod -> 0
TRACE: [394516.00] laszloMethod.apply(?undefined?, [1, 2])
laszloMethod( 1 , 2 )
TRACE: [394523.00] laszloMethod -> 0
TRACE: [394527.00] laszloMethod.apply(?undefined?, [2, 3])
laszloMethod( 2 , 3 )
TRACE: [394536.00] laszloMethod -> 0
?Array(3)#15| [1, 2, 3]?
lzx>

Oh, hah-hah. I see why. Because laslzoMethod is a method, it expects a 'this' argument, and our compiler inserts an implicit `with (this)` around your method body, but you are calling it as a function, and `this` is undefined in that case (see the trace output above). So your code is turning into `with (undefined)` and I bet that causes the global reference to Debug to fail. Amusingly, tracing the method makes the debug output work. I can't really explain that.

If you were to make a closure to call your method, it should work:

lzx> Debug.untrace(canvas, 'laszloMethod')
lzx> [1,2,3].sort(function (a, b) { return canvas.laszloMethod(a, b) })
laszloMethod( 1 , 2 )
laszloMethod( 1 , 3 )
laszloMethod( 1 , 2 )
laszloMethod( 2 , 3 )
?Array(3)#57| [1, 2, 3]?
lzx>

On 2008-01-09, at 14:28 EST, Pablo Kang wrote:


Btw, I know that I can call a laszloMethod from a Javascript function like:

<method name="javascriptFunction" args="n1,n2">
   return canvas.laszloMethod(n1,n2);
</method>

What I want to know is why it is I can't pass in the the laszloMethod directly.

Thanks,
pablo

On Wed, 9 Jan 2008, Pablo Kang wrote:


Anyone know why passing in a function defined with an LZX method tag into Array.sort doesn't work? Here's a test case:

<canvas debug="true">

<method name="laszloMethod" args="n1,n2">
   Debug.write('laszloMethod(', n1, ',', n2, ')');
    return 0;
</method>

<script>
    function javascriptFunction(n1,n2) {
        Debug.write('javascriptFunction(', n1, ',', n2 ,')');
        return 0;
    }
</script>

<handler name="oninit">
    var arr = [ 1,2,3 ];

    Debug.write('-- Javascript Function --');
    arr.sort( javascriptFunction );

    Debug.write('-- Laszlo Method --------');
    arr.sort( canvas.laszloMethod );
</handler>

</canvas>

pablo













Reply via email to