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