NS_EXTENSIBLE_STRING_ENUM Turns a groups of NSStrings into a struct. What do you suggest for the reverse? On Mon, Feb 27, 2017 at 4:39 PM Zach Waldowski via swift-evolution < swift-evolution@swift.org> wrote:
> -1 as written due to the impedance mismatch with importing NS_STRING_ENUM > and NS_EXTENSIBLE_STRING_ENUM. Exporting to Objective-C should export a > typedef and several constants, not a class. Exporting generated accessors > to Objective-C is unnecessary as you have -isEqual: and -hashValue on > NSString over there. > > I'm not sure how technically feasible it is to identify "a struct with a > single field conforming to RawRepresentable" to make it compatible with > @objc, though I'm not really a compiler person. > > Other than that, I like the idea. I don't believe any of the annotations > to make Objective-C code better in Swift should be one-way. > > Sincerely, > Zachary Waldowski > z...@waldowski.me > > > On Sun, Feb 26, 2017, at 01:21 PM, Derrick Ho via swift-evolution wrote: > > 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 > > > _______________________________________________ > 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