[Laszlo-user] Laszlo function as Array.sort argument

P T Withington ptw at pobox.com
Wed Jan 9 14:50:01 PST 2008


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
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>
>




More information about the Laszlo-user mailing list