Thursday, June 28, 2012

#as3: callbacks for inter-object communication


[post is pending for a syntax/typo check]

in an almost non-coercive attempt, here goes a short explanation of something that has already been covered by people, perhaps much more competent than me on the specific subject. if you, at one point decided to tackle performance in as3 programming, you may have eventually bumped into the subject of memory management and whether to use the event system proposed by language specification.


the as3 event system is flawed, but certainly not that bad

going to low level programming as a distant reference, an event system does not exist until you create one as model or until the operation system's client library, somehow imposes one to you. there are various topics on this subject if the as3 event system is good or not, but it is certainly widely used, yet language experts seem to criticize it a lot, thus there are alternatives like: as3-signalsfingerscjsignals.

when are callbacks a better alternative

in short, a callback is a function called by another function, when desired to pass an end result of some sort. when there are multiple instances of objects with hierarchy and inheritance, the as3 language specification suggest usage of the event system for communication between such. each time an event is dispatched memory is allocated for it to occupy and also there are possibly other function calls, assignments and overhead. even if garbage collection is as3 does a good job (to the extend you may not notice memory increase), why use the event system for really simple tasks in the first place?

consider a couple of display objects A, B, where A is parent to B (B instantiated in A).
the obvious way to communicate B -> A, would be to dispatch some sort of an event, signal or message (depending on the library you are using), but how about not creating any overhead and simply passing a data object, local to method in B as a parameter to method in A. if the object is small enough (and if AVM2 does a good job when doing stack handling) the lifetime of the object will span only trough the two methods and nothing will be ever allocated in memory (heap allocation). so basically what we are telling the VM (and before that the MIR optimizer and such) by doing this is in the rough lines of:

...
call method in B (call = )
do calculation in method (probably using the so called "local registers")
pack result into an object
push object on the stack
grab offset of method in A via a reference
call method in A (call = )
do calculation with the object (callproperty)

so no allocation and no overhead by multiple calls...but also, now consider having thousands of B instances.

here is an example using a "Delegate" object:

as3Delegate.zip


note that i advise against using "singleton" classes for inter-object communication with callbacks, unless such objects are "singletons" them self or there are no multiple instance considerations.

dynamic allocation of "enterFrame" callbacks

events such as ENTER_FRAME, that are called many times need allocation of many objects. i've read a couple of post related to the possibility of writing a different "enterFrame" and the authors have considered the method of creating a two frame MovieClip, which is basically stack-only dispatch of the event with callbacks, yet they don't find any memory or speed benefits. this is mostly, as mentioned due to the fact the GC in AVM2 is quite efficient and also due to the fact that modern machines are ridiculously fast:

http://alecmce.com/as3/replacing-enter_frame
http://blog.int3ractive.com/2010/07/myth-buster-enterframe-event.html

here is a small alternative (EnterFrame.as), which creates the two frame MovieClip dynamically instead of using library or meta data and has a much cleaner interface:

EnterFrameTest.zip

the code is based on ClipFactory by Denis Kolyako. ClipFactory is a nifty trick that creates a SWF in memory, appends a class which extends a MovieClip with a number of frames, loads the SWF, which then allows the class to be instantiated and addFrameScript() used on the frames.

EnterFrame has stop(), start(), setCallback(somemethod)


there are some drawbacks-to-callbacks

- not possible to make this work for native events such as mouse and keyboard actions, since as3 uses the event model strictly and does not provide alternatives. the criticism which was present in as2 due to a sparse implementation has turned into a restriction in as3.
- having only one centralised model for inter object communication is never a bad thing.
- closely related to the previous note, code obfuscation can become an issue when using callbacks, due to every programmer having a different naming conversation (this is a problem which an event / signal / message system certainly can solve quite well).


any event model does not cause stalls until proven guilty

and that pretty much sums it up, considering the cpu power available on the market currently. if you do not wish to optimize your message / event / signal passing method you can pretty much stay with the defaults, by proposal and if you find the interface comfortable enough, of course. in fact modern cpu are so fast that you may be hardly able to profile any code execution in research, thus leaving you with the question - "is it really worth it to even bother?".

--

0 comments: