Hey,

for completeness’ sake, I wrote a JIRA issue on this about a year ago, as 
suggested by Chris Lattner:
https://bugs.swift.org/browse/SR-583 <https://bugs.swift.org/browse/SR-583>

Opening that issue was the result of a question I asked on swift-users:
https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160111/000848.html 
<https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160111/000848.html>

… where you answered with an explanation of the situation:
https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160118/000884.html 
<https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160118/000884.html>


Also, about a year later I can report that I didn’t run into this 
NSUInteger-as-Int oddity anymore, besides the one mentioned in my message from 
a year ago. That was a case of overriding a framework class: NSSegmentedCell 
uses NSUInteger-as-Int, but my subclass thereof uses NSUInteger-as-UInt.

Regards,

Marco


> On 2017-02-02, at 02:29, Jordan Rose via swift-evolution 
> <[email protected]> wrote:
> 
> Hey, swift-evolution. I want to draw attention to one of the oddest parts of 
> the Objective-C importer today: NSUInteger. TLDR: NSUInteger is treated 
> differently based on whether it comes from a system framework or a 
> user-provided header file. I think this is silly and that we should treat it 
> consistently everywhere, but I haven’t had time to go collect data to 
> demonstrate that this is a safe change. Would someone like to take that on?
> 
> If so, read on. (Or jump to the last section, and read these “Background” 
> sections later.)
> 
> ## Background: Importing Integer Types from C
> 
> As everyone is familiar, the importer maps certain “known” Objective-C types 
> to the Swift types. This includes some mostly non-controversial mappings:
> 
> - Mapping fixed-sized integers: ‘int32_t' to ‘Int32'
> - Mapping common C types to fixed-sized integers: ‘unsigned short’ to ‘UInt16’
> - Mapping C’s ‘long’ to Swift's ‘Int’.*
> - Mapping ‘intptr_t’ and ‘ptrdiff_t’ to ‘Int’ and ‘uintptr_t’ to ‘UInt'
> - Mapping ‘NSInteger’ (and ‘CFIndex’) to ‘Int’
> 
> * ‘long’ is a pointer-sized integer on all common modern platforms except 
> 64-bit Windows; we’ll have to do something different there. (‘CLong’ will 
> always be the right type.)
> 
> And a few controversial ones:
> 
> - Both ‘size_t’ and ‘rsize_t’ are mapped to ‘Int’, not ‘UInt’. This is a 
> pragmatic decision based on Swift’s disallowing of mixed-sign arithmetic and 
> comparisons; if size_t and rsize_t really are used to represent sizes or 
> counts in memory, they will almost certainly never be greater than Int.max. 
> It’s definitely a tradeoff, though.
> 
> And finally we come to the strangest one, NSUInteger.
> 
> ## Background: NSUInteger
> 
> In (Objective-)C, NSUInteger is defined to be a word-sized unsigned integer 
> without any stated purpose, much like uintptr_t. It conventionally gets used
> 
> 1. to represent a size or index in a collection
> 2. as the base type of an enum defined with NS_OPTIONS
> 3. to store hash-like values
> 4. to store semantically-nonnegative 32-bit values, casually (as a compiler 
> writer I’d suggest uint32_t instead)
> 5. to store semantically-nonnegative 64-bit values, casually (definitely not 
> portable, would suggest uint64_t)
> 6. to store opaque identifiers known to be 32 or 64 bits (like 3, but either 
> wasting space or non-portable)
> 
> (1) is actually the problematic case. Foundation fairly consistently uses 
> NSUInteger for its collections, but UIKit and AppKit use NSInteger, with -1 
> as a common sentinel. In addition, the standard constant NSNotFound is 
> defined to have a value of Int.max, so that it’s consistent whether 
> interpreted as a signed or unsigned value.
> 
> For (2), the code really just wants a conveniently-sized unsigned value to 
> use as a bitfield. In this case the importer consistently treats NSUInteger 
> as UInt. We’re not going to talk about this case any more.
> 
> (3) is a lot like (2), except we don’t actually care what the sign of the 
> value is. We just want to vary as many bits as possible when constructing a 
> hash value; we don’t usually try to sort them (or add them, or compare them).
> 
> (4) is interesting; it’s entirely possible to have 32-bit counters that go 
> past Int32.max. It’s not common, but it’s possible.
> 
> (5) seems much less likely than (4). Int64.max is really high, and if you’re 
> already up in that range I’m not sure another bit will do you any good.
> 
> (6) is basically the same as (3); we don’t plan on interpreting these bits, 
> and so we don’t really care what sign the type has.
> 
> Because of this, and especially because of the Foundation/*Kit differences, 
> in Swift 1 we decided to import NSUInteger as Int, but only in system 
> frameworks (and when not used as the raw type of an enum). In user 
> frameworks, NSUInteger is consistently imported as UInt.
> 
> ## The Problem
> 
> This is inconsistent. User frameworks should not have different rules from 
> system frameworks. I’d like to propose that NSUInteger be imported as Int 
> everywhere (except when used as the raw type of an enum). It’s not a perfect 
> decision, but it is a pragmatic one, given Swift being much stricter about 
> mixing signedness than C. I’d hope the logic above convinces you that it 
> won’t be a disaster, either—it hasn’t been for Apple’s frameworks.
> 
> The recommended idiom for “no, really a word-sized unsigned integer” would be 
> ‘uintptr_t’, but unless you are actually trying to store a pointer as an 
> integer it’s likely that uint32_t or uint64_t would be a better C type to use 
> anyway.
> 
> For people who would suggest that Swift actually take unsigned integers 
> seriously instead of using ‘Int’ everywhere, I sympathize, but I think that 
> ship has sailed—not with us, but with all the existing UIKit code that uses 
> NSInteger for counters. Consistently importing NSUInteger as UInt would be a 
> massive source-break in Swift 4 that just wouldn’t be worth it. Given that, 
> is it better to more closely model what’s in user headers, or to have 
> consistency between user and system headers?
> 
> (All of this would only apply to Swift 4 mode. Swift 3 compatibility mode 
> would continue to do the funny thing Swift has always done.)
> 
> ## The Request
> 
> Consistently importing NSUInteger as Int would be a pretty major change to 
> how we import existing Objective-C code, and has the potential to break all 
> sorts of mixed-source projects, or even just projects with Objective-C 
> dependencies (perhaps longstanding CocoaPods). Because of this, I’ve held off 
> on proposing it for…a long time now. The last piece, I think, is to find out 
> how Objective-C projects are using NSUInteger in their headers:
> 
> - Do they have no NSUIntegers at all?
> - Are they using NSUInteger because they’re overriding something that used 
> NSUInteger, or implementing a protocol method that used NSUInteger?
> - Are they using NSUInteger as an opaque value, where comparisons and 
> arithmetic are uninteresting?
> - Are they using NSUInteger as an index or count of something held in memory?
> - Are they using NSUInteger as the raw value of an NS_OPTIONS enum?
> - Or is it something else? (These are the most interesting cases, which we 
> probably want to write down.)
> 
> If the answers all land in one of these buckets, or even 90% in one of these 
> buckets, then I think we’d be safe in proposing this change; if it turns out 
> there are many interesting uses I didn’t account for, then of course we 
> won’t. But I do think we need to do this reaserch.
> 
> Is someone willing to go look at modern CocoaPods and sample code, and ask 
> other developers from major Swift-using companies, to find out how they’re 
> using NSUInteger? And then write up their methodology and report back to us 
> at swift-evolution. If you do this, I will be quite grateful.
> 
> Thank you!
> Jordan
> 
> P.S. For Apple folks, this is rdar://problem/20347922 
> <rdar://problem/20347922>.
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to