[swift-evolution] Swift's Optional Int as NSNumber in Objective-C

Philippe Hausler phausler at apple.com
Mon May 22 11:03:20 CDT 2017



> On May 22, 2017, at 6:07 AM, Ben Rimmington <me at benrimmington.com> wrote:
> 
> 
>> On 20 May 2017, at 19:58, Philippe Hausler wrote:
>> 
>>> On May 20, 2017, at 12:25 AM, David Waite wrote:
>>> 
>>> I believe behavior depends on whether the NSNumber is the objc type or swift subtype, and whether you call the NSNumber.intValue or use Int.init?(exactly: NSNumber).
>> 
>> That part of the behavior is no longer the case. The bridge only transacts upon one number type (to leverage tagged pointers) and the subclass was removed (since it caused some gnarly inconsistencies)
> 
> The subclass `_SwiftTypePreservingNSNumber` still exists:
> 
> <https://github.com/apple/swift/blob/master/stdlib/public/SDK/Foundation/TypePreservingNSNumber.mm>

Hmm it shouldn’t, that looks like an oversight on my part if it is still alive.

> 
> Maybe the file isn't compiled anymore due to your pull requests:
> 
> <https://github.com/apple/swift/pull/9162>
> <https://github.com/apple/swift/pull/9293>

Correct. it should no longer be used (hopefully it isn’t bloating binaries with un-used code). I will look into this here shortly.

> 
> You mentioned tagged pointers. My understanding is that:
> 
> * `OBJC_TAG_NSNumber` doesn't attempt to store a `float` or `double` in the 60-bit payload;

Integral double or float values are stored (when they can be). So 42.0 will be stored, but 53.5 won’t be. All other storage types (modulo NSDecimals) will store as a tagged pointer if they can; NSNumber(value: Int32.max) on a 64 bit system will be tagged but NSNumber(value: UInt64.max) of course won’t be.

The most common floating point NSNumbers are 0.0, 1.0, -1.0, 10.0, 22.0, 0.5. But it is worth noting that since we can construct NSNumbers as cached values or even as addresses of static structures (see https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/NumberDate.subproj/CFNumber.c#L377 <https://github.com/apple/swift-corelibs-foundation/blob/master/CoreFoundation/NumberDate.subproj/CFNumber.c#L377>)



> * `OBJC_TAG_NSDate` is used only if bits 0...3 of the `NSTimeInterval` (aka `double`) are zero.

NSDates are stored as 56 bits in the tagged pointer. 

> 
> <https://opensource.apple.com/source/objc4/objc4-709/runtime/objc-internal.h.auto.html>
> 
> How often is an NSDate (with "sub-millisecond precision") created as a tagged pointer?

Not very often at all really. The most common dates are usually integral values.

> 
> — Ben
> 

To further give a bit of insight on tagged NSNumbers; using those instead of allocating a new instance each time accounts for about 1% on average for property lists. So this wasn’t really just a consistency change alone, it was execution time as well as memory fragmentation improvement.

It is also worth noting that as the overall system usage changes over time we might change our layout of tagged pointers (for both NSDate and NSNumber). So don’t rely on them being a certain way ;)





-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170522/3b580cc7/attachment.html>


More information about the swift-evolution mailing list