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
