BlitzMax optimization - Object casting
With the exception of numeric types (Byte
, Short
, Int
, Float
, Double
and Long
), all objects in BlitzMax extend the from base Object
type. This comes in handy for passing around variables that can be different types, but there’s some overhead when converting (i.e. casting) an Object
to a different type.
For example:
Type MyType
Field something:String
Method New()
Self.something = "Hello, World!"
End Method
End Type
' Create a new MyType but assign it to an Object variable.
Local o:Object = new MyType
' The following code is invalid:
' Print o.something
' The variable needs to be cast first:
Print MyType(o).something
There’s normally no need to use plain Object
types, but collections like TMap
and TList
use them for storing generic objects. This makes it easier to create lists on the fly, but comes with some overhead.
Summary
- Casting an object is approximately 8x slower than not casting.
- The size of the object (i.e. the number of fields and methods) does not affect performance.
- Casting happens automatically when iterating over a collection (such as a TList). If possible, use arrays or a strongly-typed list if frequently iterating over the same collection.
Casting benchmarks
All benchmarks are in release mode with threading enabled. Each test was executed 1,000,000,000 times.
Assignment Type | Execution Time (milliseconds) |
---|---|
No Cast | 324 |
Cast | 2849 |
The size of the object makes no difference. The same as the previous test, but with a type containing 2,000 fields:
Assignment Type | Execution Time (milliseconds) |
---|---|
No Cast | 328 |
Cast | 2916 |
Reducing casting
For collections that are large, or iterated over frequently, a strongly-typed collection will help with performance. If the size of the collection remains the same, an array will be fastest. A strongly-typed ObjectBag is almost as fast but can also be resized on the fly.
Test code
SuperStrict
Framework brl.basic
Const ITERATIONS:Int = 1000000000
Local startTime:Int
Local counter:int
' -- No Casting
Local result1:Object
Local o:Object = new MyType
startTime = millisecs()
For local i:int = 1 to ITERATIONS
result1 = o
Next
Print "No Cast: " + (millisecs() - startTime)
' -- Casting
Local result2:MyType
startTime = millisecs()
For local i:int = 1 to ITERATIONS
result2 = MyType(o)
Next
Print "Cast: " + (millisecs() - startTime)
Type MyType
Field something:String
Field something_else:Int
End Type