Casting Performance
I was reading a couple of blog posts about performance recently with trying to bring some speed to my personal project, more about that in up and coming posts. One interesting fact that keeps rearing it’s head is that we should never cast[wiki], when coding. I find this statement a little hard to stomach. I’ve been writing OOP for some years and find it hard to not cast! I try and reduce the amount of casting required by making sure I’m explicit as much as possible, but even so, you have to do it (unless some one can show me how to write a very complex project without it!).
So now we know we have to do it, what are the best ways to do it. I was running some tests last night and I was actually surprised that I didn’t know this, because it’s obvious.
I made a test which just loops through a for loop attempting to cast various items or the iterator. It’s fairly explanatory, just run the for loops multiple times until you get a big enough delta between beforeTime and the current time to make any sense.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | const NUM_ITERATIONS : int = 1000000; var i : int = 0; var beforeTime : int; var element : IElement = ElementFactory.create(); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item0 : Element = Element(element); } trace("\tCast method (Class(instance)): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item1 : Element = element as Element; } trace("\tCast method (instance as Class): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item2 : int = int(i); } trace("\tCast method (int(instance)): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item3 : int = i as int; } trace("\tCast method (instance as int): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item4 : String = String(i); } trace("\tCast method (String(instance)): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item5 : String = i as String; } trace("\tCast method (instance as String): " + (getTimer()-beforeTime)); beforeTime = getTimer(); for(i=0; i<= NUM_ITERATIONS; ++i) { var item6 : String = i.toString(); } trace("\tCast method (instance.toString()): " + (getTimer()-beforeTime)); |
So the results:
Cast method (Class(instance)): 6
Cast method (instance as Class): 75
Cast method (int(instance)): 3
Cast method (instance as int): 61
Cast method (String(instance)): 407
Cast method (instance as String): 67
Cast method (instance.toString()): 478
So what does this mean?
To keep it short. Don’t cast to another type, so don’t go from int to String, use ‘as’. Don’t use the toString() method for casting a int to a string, it’s very costly.
This is the important bit: Only if you know what the instance is it safe to do a cast and make sure you don’t use ‘as’. So if you know it’s an Element because of the IElement interface or because of a way to quickly test it (enum class which you define), then use type conversion.
Casting is expensive if you do it wrong, so make sure you do it correctly.
Note:
I tested this with the latest Flash Player 10.1 b3, so this could all change. I’ve not tested with old Flash Players because I’ve got better things to do! Also test with the normal release and not the debugger, I can not emphasis that enough!
Update:
This (i as String) would equal null, I should of checked this.