I updated my proposal <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md> to reflect the community's desire to build on @objc instead of adding a new attribute @objcstring.
I've included it below for convenience: Swift Enum strings ported to Objective-c - Proposal: SE-NNNN <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-filename.md> - Authors: Derrick Ho <https://github.com/wh1pch81n> - Review Manager: TBD - Status: Awaiting review *During the review process, add the following fields as needed:* - Decision Notes: Rationale <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161114/028950.html> - Previous Proposal: SE-0033 <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/0033-import-objc-constants.md> <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#introduction> Introduction We should allow swift-enum-strings and swift-struct-strings to be bridged to objective-c. We can use the following notation: @objc enum Planets: String { case Mercury } @objc struct Food: String { public static let hamburger = Food(rawValue: "hamburger") } Creating a bridgable version will allow objective-c to enjoy some of the benefits that swift enjoys. Swift-evolution thread: Discussion <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161114/028950.html> Discussion <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170220/032656.html> <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#motivation> Motivation NS_STRING_ENUM and NS_EXSTENSIBLE_STRING_ENUM are annotations that you can add to an objective-c global string. The annotations will make swift interpret the objective-c global strings as enum and structs respectively in theory. But it actually doesn't ever create enums <https://bugs.swift.org/browse/SR-3146>. The problem seems to stem from the conversion from objc to swift. It might be more fruitful to make a conversion from swift to objc. However, what if we take it a step further? Turning a swift-string-enum into a bunch of global NSStrings really limits its power. There are many classes written by apple that are structs in swift but become classes in objective-c (i.e. String becomes NSString, Date becomes NSDate, Array becomes NSArray, etc). There is a special bridging mechanism that allows this to be possible. I think we should expand on that. <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#proposed-solution>Proposed solution // `@objc` and `String` can be applied to an enum to make it available to objective-c: // @objc public enum Food: String { case Calamari case Fish } // This can be ported over to Objective-c as an objective-c class @interface Food: NSObject @property (readonly) NSString *_Nonnull rawValue; - (instancetype _Nullable)initWithRawValue:(NSString *_Nonnull)rawValue; + (instanceType _Nonnull)Calamari; + (instanceType _Nonnull)Fish; @end // `@objc` and `String` can be applied to a struct to make it available to objective-c: // @objc public struct Planets: String { public let rawValue: String //<- This should be implicit and the user should not need to add it init(rawValue: String) { self.rawValue = rawValue } //<- This should be implicit and the user should not need to add it public static let Earth = Planets(rawValue: "Earth") //<- user defines these public static let Venus = Planets(rawValue: "Venus") //<- user defines these } // This can be ported over to objective-c as a class @interface Planets: NSObject - (instancetype _Nonnull)initWithRawValue:(NSString *_Nonnull)rawValue; + (instancetype)Earth; + (instancetype)Venus; @end The difference between a swift-enum-string and a swift-struct-string is that swift-enum-string provides a failable initializer while swift-struct-string provides a non-failable initializer. <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#detailed-design>Detailed design <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-string-enum---casestring-translations>swift-string-enum - case/string translations A swift-enum-string, is created with cases and it has an implicit string value based on the name of the case. The user may also add a name that does not equal the name of the case. // Swift @objc public enum Food: String { case Calamari case Fish = "Flounder" //<-- User wants Fish to be Flounder } // Objective-c @interface Food: NSObject @property (readonly) NSString *_Nonnull rawValue; + (instanceType _Nonnull)Calamari; + (instanceType _Nonnull)Fish; @end @implementation Food + (instanceType _Nonnull)Calamari { return [[Food alloc] initWithRawValue:@"Calimari"]; } + (instanceType _Nonnull)Fish { return [[Food alloc] initWithRawValue:@"Flounder"]; } //<-- Fisher contains Flounder @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-string-enum---failable-initializer>swift-string-enum - failable initializer A swift-enum-string has the ability to be initialized with a string. If the string matches one of the possible cases, then it returns it, otherwise it will return nil. This feature might be implemented as a dictionary or some other means that gets the same results; Below is my suggestion. // Assuming this swift implementation @objc public enum Food: String { case Calamari case Fish = "Flounder" //<-- User wants Fish to be Flounder } // The objective-c failable initializer may look like this. @implementation Food - (instancetype _Nullable)initWithRawValue:(NSString *_Nonnull)rawValue { static NSDictionary <NSString *, NSString *>*states; if (!states) { // A dictionary where the KEYs are the acceptable rawValue's and the VALUE are empty strings states = @{ @"Calimari" : @"", @"Flounder" : @"" } } if ((self = [super init])) { if (states[rawValue]) { _rawValue = rawValue return self; } } return nil; } @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-string-enum---methods>swift-string-enum - methods swift enums allow methods to be defined. If you mark a method with @objc it should be made available to objective-c. // Swift @objc public enum Food: String { case Calamari case Fish @objc func price() -> Double { // ... } } // Objective-c @interface Food: NSObject // ... - (Double)price; // ... @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-struct-string---string-translations>swift-struct-string - string translations A swift-struct-string needs to be marked with @objc and inherit from String to bridge to objective-c. A property or method must be marked with @objc to be made available to objective-c. // Swift @objc struct Planet { @objc public static let Earth = Planet(rawValue: "Earth") @objc public func distanceFromSun() -> Double { ... } } // Objective-c @interface Planet + (instancetype _Nonnull)Earth; + (Double)distanceFromSun; @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-struct-string---non-failable-initializer>swift-struct-string - non-failable initializer The swift-struct-string initializer should not be failable and will accept any string value @implementation Planet - (instancetype _Nonnull)initWithRawValue:(NSString *)rawValue { if ((self = [super init])) { _rawValue = rawValue; } return self; } @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-struct-string---extension>swift-struct-string - extension One of the key attributes of an extensible string enum is that it can be extended. This should produce something available to objective-c. The original definition of Planet needs to have been marked with @objc. // Swift extension Planet { @objc public static let Pluto = Planet(rawValue: "Pluto") } // Objective-c @interface Planet (extention_1) - (instancetype _Nonnull)Pluto; @end @implementation Planet (extention_1) - (instancetype _Nonnull)Pluto { return [[Planet alloc] initWithRawValue:@"Pluto"]; } @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#swift-string-enum--swift-struct-string---equalityhashrawvalue>swift-string-enum && swift-struct-string - equality/hash/rawValue When an enum or struct is marked with @objc and String, the objective-c class that is produced should have its equality/hash methods and rawValue property implicitly be implemented. The user should not need to implement these on his/her own. @implementation Food - (instancetype)rawValue { return _rawValue; } - (NSUInteger)hash { return [[self rawValue] hash]; } - (BOOL)isEqual:(id)object { if (self == object) { return YES } if (![object isKindOfClass:[Food class]]) { return NO; } return [self.rawValue isEqualToString:((Food *)object).rawValue]; } @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#objective-c-name>Objective-c name In the above examples, the objective-c name of the class and the swift name of the class were the same. If this causes a naming conflict then the objective-c name could be Prefixed with ENUM. // Swift @objc enum Planet: String { ... } // Objective-c @interface ENUMPlanet @end The programmer should still be able to add their own name by specifying it as an argument. // Swift @objc(CustomPlanet) enum Planet { ... } // Objective-c @interface CustomPlanet @end <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#source-compatibility>Source compatibility This will be an additive feature and will not break anything existing. <https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md#alternatives-considered>Alternatives considered - Implement a swift class that implements the above described behviors. - Don't change anything. On Tue, Feb 21, 2017 at 6:09 PM Derrick Ho <wh1pch...@gmail.com> wrote: > True. > In my proposal I mention how NS_STRING_ENUM doesn't produce an swift enum. > > So one solution is to merely "go the other way" which would produce what > Kevin N. suggested. > > Is it not odd that that the objc version is so different from the swift > version? > > Would it not be better to offer a somewhat similar API experience between > the two languages? > > @objcstring would "promote" the swift enum to an objective-c class to make > the API experience similar. > > I understand that maybe @objcstring is too niche to get its own > annotation. Instead @objc should become more powerful. > > I think @objc should make an enum become a class with swift-enum like > abilities. This would allow enum functions to be bridged over to > objective-c as well. > On Tue, Feb 21, 2017 at 1:32 PM Michael Ilseman <milse...@apple.com> > wrote: > > A quick note addressing a misconception that you’ll want to clean up for a > formal proposal: > > NS_[EXTENSIBLE_]STRING_ENUMs both generate Swift structs, the difference > is only in the explicitness of the rawValue initializer. To use the “other > direction” analogy, you’d similarly want them to apply for rawValue-ed > structs alone. The reasons are the same: only the structs are > layout-compatible because enums are integers. > > Once you go down this route, perhaps it doesn’t make sense to annotate the > struct decls themselves anymore. Maybe you just want more @objc control > over bridging the types. For example, maybe you want to introduce a feature > so that static members that are layout-compatible with String are bridged > as global strings with the supplied name. > > > > > On Feb 20, 2017, at 4:07 PM, Derrick Ho via swift-evolution < > swift-evolution@swift.org> wrote: > > Swift should not forsake objective-c. At least not when it comes enum > strings. Although swift enums are suppose to be swift only, I think we > should add a new attribute to slightly relax that. I think a good > attribute would be @objcstring. > > By adding @objcstring, an objective-c exclusive class will be generated. > > @objcstring > enum Planet { > case Jupiter > } > > I have written up a proposal with more details on what it would look for > objective-c. > > > https://github.com/wh1pch81n/swift-evolution/blob/swift-enum-objc/proposals/NNNN-Swift-enum-strings-ported-to-Objective-c.md > > If no one objects to this proposal I'll submit it. > > **notes: I am reviving this discussion so that I may submit this for Swift > 4 stage 2 > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution