> On Dec 21, 2015, at 2:38 PM, Brent Royal-Gordon via swift-evolution 
> <[email protected]> wrote:
> 
>> One of the things that surprised me is that there still isn’t concise syntax 
>> for creating option sets, a pattern I see out in the wild a fair bit.  While 
>> Swift 2 did introduce OptionSetType for structs, it still feels somewhat 
>> obtuse and non-obvious.  It would be great if we could something like:
>> 
>> options NotSoSecretVariations {
>>      case ProteinStyle,
>>      case AnimalStyle,
>>      case GrilledOnions,
>>      ...
>> }
>> 
>> That said, I have a feeling this isn’t the first time the Swift team has 
>> come across a pitch like this.  If this really is unfeasible, it would be 
>> great and really educational to hear what the challenges are.
> 
> Personally, what I'd like to see is the concept of an option separated from 
> that of an option *set*. Once you do that, you can define an individual 
> option simply using an enum, and let the set handle combining the options 
> together.
> 
> Here's what I mean. Take an Objective-C NS_OPTIONS enum:
> 
>       typedef NS_OPTIONS(NSUInteger, NSStringCompareOptions) {
>           NSCaseInsensitiveSearch = 1,
>           NSLiteralSearch = 2,                /* Exact character-by-character 
> equivalence */
>           NSBackwardsSearch = 4,              /* Search from end of source 
> string */
>           NSAnchoredSearch = 8,               /* Search is limited to start 
> (or end, if NSBackwardsSearch) of source string */
>           NSNumericSearch = 64,               /* Added in 10.2; Numbers 
> within strings are compared using numeric value, that is, Foo2.txt < Foo7.txt 
> < Foo25.txt; only applies to compare methods, not find */
>           NSDiacriticInsensitiveSearch NS_ENUM_AVAILABLE(10_5, 2_0) = 128, /* 
> If specified, ignores diacritics (o-umlaut == o) */
>           NSWidthInsensitiveSearch NS_ENUM_AVAILABLE(10_5, 2_0) = 256, /* If 
> specified, ignores width differences ('a' == UFF41) */
>           NSForcedOrderingSearch NS_ENUM_AVAILABLE(10_5, 2_0) = 512, /* If 
> specified, comparisons are forced to return either NSOrderedAscending or 
> NSOrderedDescending if the strings are equivalent but not strictly equal, for 
> stability when sorting (e.g. "aaa" > "AAA" with NSCaseInsensitiveSearch 
> specified) */
>           NSRegularExpressionSearch NS_ENUM_AVAILABLE(10_7, 3_2) = 1024    /* 
> Applies to rangeOfString:..., stringByReplacingOccurrencesOfString:..., and 
> replaceOccurrencesOfString:... methods only; the search string is treated as 
> an ICU-compatible regular expression; if set, no other options can apply 
> except NSCaseInsensitiveSearch and NSAnchoredSearch */
>       };
> 
> I think this should be translated to Swift like this:
> 
>       enum NSStringCompareOption: Int {
>           case CaseInsensitiveSearch = 0      // Because 1 << 0 == 1
>           case LiteralSearch = 1      // 1 << 1 == 2
>           case BackwardsSearch = 2
>           case AnchoredSearch = 3
>           case NumericSearch = 6      // 1 << 6 == 64
>           case DiacriticInsensitiveSearch = 7
>           case WidthInsensitiveSearch = 8
>           case ForcedOrderingSearch = 9
>           case RegularExpressionSearch = 10
>       }
> 
> Meanwhile, a method taking NSStringCompareOptions like this:
> 
>       - (NSComparisonResult)compare:(NSString *)string 
> options:(NSStringCompareOptions)mask;
> 
> Should be translated as:
> 
>       func compare(string: NSString, options mask: 
> OptionSet<NSStringCompareOption>) -> NSComparisonResult
> 
> OptionSet would be a generic type like this:
> 
>       struct OptionSet<Option: RawRepresentable where Option.RawValue: 
> IntegerType>: SetAlgebraType, RawRepresentable {
>           typealias Element = Option
>           typealias RawValue = Option.RawValue
>           ...
>       }
> 
> This definition should work for any NS_OPTIONS where the options are 
> non-overlapping. I'm not sure if that's *every* option set in the Apple 
> frameworks, but I think it's the vast majority of them. (The incompatible 
> ones could use the existing mechanism.) And to create your own option set, 
> all you have to do is write an enum with an integer raw type that has less 
> than 32 or 64 cases, depending on your target. You don't even have to specify 
> the raw values—the default ones will work fine.

One reason we preserved the NS_OPTIONS model, where single options share the 
same type as option sets, is that it allows for API evolution. A library can 
break a single option down into multiple refined options while still offering 
the original option as the union of the new ones. So you can go from:

public struct LaundryOptions: OptionSetType {
  public static let EnergyStar = 1
}

to:

public struct LaundryOptions: OptionSetType {
  public static let EnergyStar: LaundryOptions = [.LowWater, .LowHeat]
  public static let LowWater = 1, LowHeat = 2
}

without breaking client code (or at least, client code that doesn't attempt to 
inspect the option set itself).

-Joe

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to