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

P T Withington ptw at pobox.com
Wed Jan 9 14:07:05 PST 2008


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