<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 20, 2016, at 6:39 PM, Jeff Kelley &lt;<a href="mailto:slaunchaman@gmail.com" class="">slaunchaman@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class="">On Jan 20, 2016, at 7:41 PM, Douglas Gregor &lt;<a href="mailto:dgregor@apple.com" class="">dgregor@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 20, 2016, at 2:11 PM, Jordan Rose &lt;<a href="mailto:jordan_rose@apple.com" class="">jordan_rose@apple.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Jan 17, 2016, at 22:10 , Douglas Gregor via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class=""><div class=""><br class="Apple-interchange-newline">On Jan 17, 2016, at 7:13 PM, Jeff Kelley via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">A lot of Cocoa APIs have long lists of constant values, typically<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">NSString</font>s. I’d like to pitch a way to import them as<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">enum</font>s with associated types. I can write up a full proposal if people think this is a good idea, but here’s my thinking:</div><div class=""><br class=""></div><div class="">Let’s take the error domains in<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">NSError.h</font><span class="Apple-converted-space">&nbsp;</span>for a quick example. These entries in the header:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class=""><blockquote type="cite" class="">FOUNDATION_EXPORT NSString *const&nbsp;NSCocoaErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSPOSIXErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSOSStatusErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSMachErrorDomain;</blockquote></font></div><div class=""><br class=""></div><div class="">turn into this in the Swift interface:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class=""></font></div><blockquote type="cite" class=""><div class=""><font face="Menlo" class="">public&nbsp;let&nbsp;NSCocoaErrorDomain:&nbsp;String<br class="">public&nbsp;let&nbsp;NSPOSIXErrorDomain:&nbsp;String<br class="">public&nbsp;let&nbsp;NSOSStatusErrorDomain:&nbsp;String<br class="">public&nbsp;let&nbsp;NSMachErrorDomain:&nbsp;String</font></div></blockquote><div class=""><br class=""></div><div class="">What I’m proposing is a way to import those as an<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">enum</font><span class="Apple-converted-space">&nbsp;</span>instead. Similar to how we mark sections of Objective-C code with<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">NS_ASSUME_NONNULL_BEGIN</font>, we could mark it with something like<span class="Apple-converted-space">&nbsp;</span><font face="Menlo" class="">NS_CASE_LIST_BEGIN</font>. Then, this code:</div><div class=""><br class=""></div><div class=""></div><blockquote type="cite" class=""><div class=""><font face="Menlo" class="">NS_CASE_LIST_BEGIN;</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">FOUNDATION_EXPORT NSString *const&nbsp;NSCocoaErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSPOSIXErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSOSStatusErrorDomain;<br class="">FOUNDATION_EXPORT NSString *const&nbsp;NSMachErrorDomain;</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">NS_CASE_LIST_END;</font></div></blockquote><div class=""><br class=""></div><div class="">would be imported as follows:</div><div class=""><br class=""></div><font face="Menlo" class=""></font><div class=""></div><blockquote type="cite" class=""><font face="Menlo" class="">enum&nbsp;ErrorDomain :&nbsp;String&nbsp;{<br class="">&nbsp; &nbsp;&nbsp;case&nbsp;Cocoa<br class="">&nbsp; &nbsp;&nbsp;case&nbsp;POSIX<br class="">&nbsp; &nbsp;&nbsp;case&nbsp;OSStatus</font><div class=""><font face="Menlo" class="">&nbsp; &nbsp; case Mach<br class="">}</font></div></blockquote><div class=""><br class=""></div><div class="">I can think of a lot of areas in Cocoa where these APIs could make things much more type-safe in Swift. Is this a good idea? Would people use this?<br class=""></div></div></div></blockquote></div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">FWIW, this has come up a number of times in discussions among Swift developers (although not, IIRC, on swift-evolution). Our current favored way to write this in (Objective-)C would be with a new typedef of NSString * that has some special attribute on it, e.g.,</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">&nbsp; typedef NSString * NSErrorDomain __attribute__((enum(string)));</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">&nbsp; FOUNDATION_EXPORT NSErrorDomain const NSCocoaErrorDomain;</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="">&nbsp; FOUNDATION_EXPORT NSErrorDomain const NSPOSIXErrorDomain;</div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="">&nbsp; FOUNDATION_EXPORT NSErrorDomain const NSOSStatusErrorDomain;</div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><div class="">&nbsp; FOUNDATION_EXPORT NSErrorDomain const NSMachErrorDomain;</div></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">The typedef would import as a String-backed enum and all of the string constants declared with that typedef within the same module as the typedef would become cases of that enum. String constants declared with that typedef in a *different* module would become “static lets” within extensions of the String-backed enum.</div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">Call that a +1 from me on your idea :)</div></div></blockquote><br class=""></div><div class="">I still have reservations about this:</div><div class=""><br class=""></div><div class="">- Most of these strings are not things you switch on, making the enum-ness not particularly interesting. I'd be happier with a RawRepresentable struct.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I think a RawRepresentable struct captures the intended semantics well. Jeff, what do you think?</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">I haven’t used RawRepresentable by itself before. Is this the kind of result we’d get?</div><div class=""><br class=""></div></div><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><font face="Menlo" class="">struct&nbsp;NSErrorDomain:&nbsp;RawRepresentable&nbsp;{</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;static&nbsp;let&nbsp;Cocoa:&nbsp;MyRelatedValue</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;static&nbsp;let&nbsp;POSIX:&nbsp;MyRelatedValue</font></div></div><div class=""><div class=""><span class="" style="font-family: Menlo;">&nbsp; &nbsp;&nbsp;</span><span class="" style="font-family: Menlo;">static</span><span class="" style="font-family: Menlo;">&nbsp;</span><span class="" style="font-family: Menlo;">let</span><span class="" style="font-family: Menlo;">&nbsp;OSStatus:&nbsp;</span><span class="" style="font-family: Menlo;">MyRelatedValue</span></div></div><div class=""><div class=""><span class="" style="font-family: Menlo;">&nbsp; &nbsp;&nbsp;</span><span class="" style="font-family: Menlo;">static</span><span class="" style="font-family: Menlo;">&nbsp;</span><span class="" style="font-family: Menlo;">let</span><span class="" style="font-family: Menlo;">&nbsp;Mach:&nbsp;</span><span class="" style="font-family: Menlo;">MyRelatedValue</span></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;</font></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;typealias&nbsp;RawValue =&nbsp;String</font></div></div></blockquote></div></blockquote><blockquote type="cite" class=""><div class=""><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><span style="font-family: Menlo;" class="">&nbsp; &nbsp;&nbsp;</span></div></div><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;init?(rawValue:&nbsp;RawValue)</font></div></div></blockquote></div></blockquote><div><br class=""></div><div>This initializer should be non-failable; we’ll accept any raw value.</div><div><br class=""></div><blockquote type="cite" class=""><blockquote class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><div class=""><font face="Menlo" class="">&nbsp; &nbsp;&nbsp;var&nbsp;rawValue:&nbsp;String&nbsp;&nbsp;{ get }</font></div></div></blockquote></blockquote><div><br class=""></div><div>Otherwise, yes, this is it.</div></div><div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">If so, I think that has the same benefits of an enum without the added baggage. We get a type for the values, a list of the public instances of the value, and the typedef in Objective-C even makes that language more readable. As long as we can still get to an instance of the value using the short dot syntax:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span><font face="Menlo" class="">let foo: NSErrorDomain = .Cocoa</font></div></div></div></blockquote><div><br class=""></div><div>Yes, that works with static lets.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">Then I see no downside to a struct vs. an enum. The only reason I’d thought of an enum in the first place was that I’ve seen existing Swift code use enums to group related strings—user defaults keys, etc.</div></div></div></blockquote><div><br class=""></div>Right. struct seems to model the uses of these string constants betters. FWIW, I suggest that you put “String” somewhere in the title of your proposal when you revise it.</div><div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">Adding a new value in the future should definitely be as straightforward as possible, but I’m not sure what about this approach makes that more difficult.</div></div></blockquote><div><br class=""></div><div>I think it’s just a matter of declaring a new constant on the Objective-C side, and it’ll get pulled into the struct definition or (if the new constant is in a different module) an extension thereof.</div></div><br class=""><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>- Doug</div><div class=""><br class=""></div></body></html>