What are the different runtime costs incurred by the following type casts?
Numeric cast of constant, e.g.:
let f = 0.1 as CGFloat
I'd imagine this has zero runtime cost.
Numeric cast of runtime value, e.g.:
let f = someDoubleValue as CGFloat
I'd imagine this has an extremely small runtime cost.
Upcast, e.g.:
let dict: [String: Int] = ...
let anyObj = dict as AnyObject
I'd expect this to have zero runtime cost.
Failable Downcast, e.g.:
let anyObj: AnyObject = ...
if let str = anyObj as? String { ... }
I'd expect this to have a runtime cost proportional to the number of classes in the hierarchy of the dynamic type of anyObj
.
Forced Downcast, e.g.:
let anyObj: AnyObject = ...
let str = anyObj as! String
Maybe the cost for a forced downcast is slightly lower?
Forced Downcast of collection, e.g.:
let dates: [AnyObject] = ...
for date in dates as! [NSDate] { ... }
What happens here — especially when dates
comes from an NSArray
? Is the runtime cost of this cast proportional to the number of its elements? What if I cast to a more complex collection type like [String: [String: [Int]]]
— is the whole collection traversed to make sure all its elements and subelements conform to this cast?
For each of the first four cases, are my assertions true?
It is O(1) (almost 0) if it is obviously castable(like numeric casting and upcasting): case 1, 2, 3.
For other non-collection castings, it is obviously O(1): case 4, 5.
For collection downcastings:
as?
is O(n) because element type checking is performed eagerly.NSArray as! [NSDate]
) is O(n) because element type checking is performed eagerly.Sources:
Just wanted to add that the runtime cost of protocol typecast is horrific. I tried to look at it in disassembly view and simply lost track of what's happening. So a line like this:
(self as! SomeProtocol).someMethod()
results in retain/release (which involve memory barriers), then there's a call to the old good objc_msgSend()
(!) but not related to someMethod()
, I presume because one of self
or SomeProtocol
are derived from class
, and then a very very long chain of function calls with some loops involved. Like I said I lost patience trying to debug this single line of code in disassembly view.
While protocols are a really nice abstraction, they should be used sparingly in performance critical code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With