> 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