<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I know I’m late to the party and the review period has ended, but I’d like to add a suggestion towards a possible solution to a point that was discussed in this context.</div><br class=""><div><blockquote type="cite" class=""><div class="">On 2016-02-05, at 17:54, Michel Fortin via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div class=""><br class=""></div></div></blockquote><blockquote type="cite" class="">[…]</blockquote><blockquote type="cite" class=""><br class=""></blockquote><blockquote type="cite" class=""><div class=""><div class="">Eventually, classes such as NSCountedSet and NSIndexSet will have a proper struct wrapper that will claim the non-prefixed name. But there is no urgency in making those wrappers ready for Swift 3 because the class remains available.<br class=""><br class="">Anyway, that's what I'd propose. There aren't that many classes in Foundation; cases like this can be sorted out manually.<br class=""></div></div></blockquote></div><br class=""><div class="">I wholeheartedly agree with this: I’d take a close look at every <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span> in Foundation that should really be a value type in Swift (all collection types, NSURL, …) and keep the NS prefix for them. Then, at some later point (or with Swift 3 if there’s enough time), add <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span> wrappers without the NS prefix for these <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es.</div><div class=""><br class=""></div><div class="">I want to outline a possible solution to this that allows all developers to annotate their <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es and have them automatically imported as <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>s in Swift.</div><div class="">I think that could actually work with just a couple of annotations in the Objective-C headers and the correct interpretation of them in the Clang Importer. I’d propose something like this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">@interface</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #78492a" class="">NS_SWIFT_STRUCT</span><span style="font-variant-ligatures: no-common-ligatures" class="">(CountedSet) NSCountedSet<ObjectType> : </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">NSMutableSet</span><span style="font-variant-ligatures: no-common-ligatures" class=""><ObjectType> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><div style="margin: 0px; line-height: normal; color: rgb(187, 44, 162);" class=""><div style="margin: 0px; line-height: normal; color: rgb(0, 132, 0);" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">@property</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">BOOL</span><span style="font-variant-ligatures: no-common-ligatures; color: #000000" class=""> foo; </span><span style="font-variant-ligatures: no-common-ligatures" class="">// Just for demonstration purposes.</span></div></div></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">- (NSUInteger)countForObject:(ObjectType)object;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">- (</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">void</span><span style="font-variant-ligatures: no-common-ligatures" class="">)addObject:(ObjectType)object </span><span style="font-variant-ligatures: no-common-ligatures; color: #78492a" class="">NS_SWIFT_MUTATING</span><span style="font-variant-ligatures: no-common-ligatures" class="">;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">- (</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">void</span><span style="font-variant-ligatures: no-common-ligatures" class="">)removeObject:(ObjectType)object </span><span style="font-variant-ligatures: no-common-ligatures; color: #78492a" class="">NS_SWIFT_MUTATING</span><span style="font-variant-ligatures: no-common-ligatures" class="">;</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""></span><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class="">…</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; min-height: 13px;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(187, 44, 162);" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">@end</span></div></div><div class=""><br class=""></div><div class="">In Swift, that would come through as the following (in addition to an NSCountedSet class):</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">struct</span><span style="font-variant-ligatures: no-common-ligatures" class=""> CountedSet<ObjectType> {</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">private let</span><span style="font-variant-ligatures: no-common-ligatures" class=""> _internal: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">NSCountedSet</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">var</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> foo: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Bool</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> countForObject(object: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">ObjectType</span><span style="font-variant-ligatures: no-common-ligatures" class="">) -> </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">Int</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">mutating</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> addObject(object: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">ObjectType</span><span style="font-variant-ligatures: no-common-ligatures" class="">)</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">mutating</span><span style="font-variant-ligatures: no-common-ligatures" class=""> </span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> removeObject(object: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">ObjectType</span><span style="font-variant-ligatures: no-common-ligatures" class="">)</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><br class=""></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""> …</div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class=""><br class=""></span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">}</span></div></div><div class=""><br class=""></div><div class="">That is: <span style="color: rgb(120, 73, 42); font-family: Menlo; font-size: 11px;" class="">NS_SWIFT_STRUCT(_name)</span> specifies that a <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span> with the given <span style="color: rgb(120, 73, 42); font-family: Menlo; font-size: 11px;" class="">_name</span> should be created that has a <span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">private let</span> member of the annotated <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>. All methods of the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span> and all its superclasses are automatically imported as methods of the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>. Methods annotated as <span style="color: rgb(120, 73, 42); font-family: Menlo; font-size: 11px;" class="">NS_SWIFT_MUTATING</span> are imported as <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">mutating</span> methods in the Swift <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>. For <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">@property</span> declarations, the importer could automatically infer that the setter is <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">mutating</span> and the getter <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">nonmutating</span>, although an <span style="color: rgb(120, 73, 42); font-family: Menlo; font-size: 11px;" class="">NS_SWIFT_NONMUTATING</span> might be useful to annotate that a property setter should be imported as <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">nonmutating</span>, if applicable.</div><div class=""><br class=""></div><div class=""><div class="">After a quick glance over all of Foundation’s <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es, I think the following could be eligible (probably not a complete list):</div><div class=""><div class="">NSAttributedString</div><div class="">NSCharacterSet</div><div class="">NSCountedSet</div><div class="">NSData</div><div class="">NSDate</div><div class="">NSDecimalNumber</div><div class="">NSError</div><div class="">NSHashTable</div><div class="">NSIndexPath</div><div class="">NSIndexSet</div><div class="">NSNotification</div><div class="">NSNumber/NSValue</div><div class="">NSOrderedSet</div><div class="">NSURL</div><div class="">NSUUID</div></div><div class=""><div class=""><br class=""></div></div><div class="">Whereas for some classes it would be better to use the mutable variants as the internal storage for the Swift <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>:</div><div class=""><div class="">NSMutableAttributedString (as AttributedString)</div><div class="">NSMutableCharacterSet (as CharacterSet)</div><div class="">NSMutableData (as Data)</div><div class="">NSMutableIndexSet (as IndexSet)</div><div class="">NSMutableOrderedSet (as OrderedSet)</div></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The Clang Importer could also handle the case where passing a Swift URL to an Objective-C method that expects an NSURL could work automatically. Maybe an Objective-C methods like this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures" class="">- (</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">void</span><span style="font-variant-ligatures: no-common-ligatures" class="">)methodImplementedInObjectiveC:(<span style="color: rgb(112, 61, 170);" class="">NSURL</span> *)arg;</span></div></div><div class=""><br class=""></div><div class="">… could be imported into Swift like this:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> methodImplementedInObjectiveC(arg: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">NSURL</span><span style="font-variant-ligatures: no-common-ligatures" class="">)</span></div><div style="margin: 0px; font-size: 11px; line-height: normal; font-family: Menlo;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">func</span><span style="font-variant-ligatures: no-common-ligatures" class=""> methodImplementedInObjectiveC(</span><span style="font-variant-ligatures: no-common-ligatures; color: #bb2ca2" class="">inout</span><span style="font-variant-ligatures: no-common-ligatures" class=""> arg: </span><span style="font-variant-ligatures: no-common-ligatures; color: #703daa" class="">URL</span><span style="font-variant-ligatures: no-common-ligatures" class="">) </span><span style="color: rgb(0, 132, 0);" class="">// Objective-C code operates on arg._internal</span></div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">If the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span> wraps a class that has a mutable counterpart (this would have to be annotated somehow), the import could do a better job for the nonmutating variant. This would require a variant of the <span style="color: rgb(120, 73, 42); font-family: Menlo; font-size: 11px;" class="">NS_SWIFT_STRUCT(_name) </span>macro that takes another parameter that points to the nonmutating variant. Then, the following methods:</div><div class=""><br class=""></div><div class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">- (</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">void</span><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class="">)nonmutatingMethodImplementedInObjectiveC:(<span style="color: rgb(112, 61, 170);" class="">NSData</span> *)arg;</span></div><div class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""><span style="font-variant-ligatures: no-common-ligatures;" class="">- (</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">void</span><span style="font-variant-ligatures: no-common-ligatures;" class="">)mutatingMethodImplementedInObjectiveC:(<span style="color: rgb(112, 61, 170);" class="">NSMutableData</span> *)arg;</span></span></div><div class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div><div class=""><div class=""><div class="">… could be imported into Swift like this:</div></div></div><div class=""><br class=""></div><div class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">func</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> nonmutatingMethodImplementedInObjectiveC(arg: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Data</span><span style="font-variant-ligatures: no-common-ligatures;" class="">)</span></div><div style="margin: 0px; line-height: normal;" class=""><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">func</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> mutatingMethodImplementedInObjectiveC(</span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(187, 44, 162);" class="">inout</span><span style="font-variant-ligatures: no-common-ligatures;" class=""> arg: </span><span style="font-variant-ligatures: no-common-ligatures; color: rgb(112, 61, 170);" class="">Data</span><span style="font-variant-ligatures: no-common-ligatures;" class="">) </span><span style="color: rgb(0, 132, 0);" class="">// Objective-C code operates on arg._internal</span></div></span></div><div class=""><span style="font-family: Menlo; font-size: 11px; font-variant-ligatures: no-common-ligatures;" class=""><br class=""></span></div><div class=""><br class=""></div><div class="">Annotations like this would be very useful because it would also allow developers to annotate their own <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es like this. It’s not uncommon to have model objects that could sensibly be <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>s in Swift, but can’t because existing Objective-C code requires them to be <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es.</div><div class=""><br class=""></div><div class=""><div class="">When Objective-C <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es become Swift <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>s, they obviously lose their inheritance chain and therefore polymorphic properties. I haven’t done a survey, but my gut feeling tells me that the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es for which all this is relevant – i.e. those that should have value semantics – aren’t usually subclassed and this point could therefore be moot. I may be wrong about that, though.</div></div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">There are probably a lot of additional things to specify here, but maybe this could be a way forward. It would enable using things like NSCountedSet and NSURL in Swift just like it does now, with the possibility to add value types for them later without breaking existing code. In time, the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">class</span>es could also be deprecated in favor of the <span style="color: rgb(187, 44, 162); font-family: Menlo; font-size: 11px;" class="">struct</span>, if that is desired.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Cheers,</div><div class=""><br class=""></div><div class="">Marco</div></body></html>