Reducing Array<OptionSet> to OptionSet


(Jon Shier) #1

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {
    
    func reduced() -> Iterator.Element {
        return reduce(Iterator.Element()) {
            var newResult = $0
            newResult.insert($1)
            return newResult
        }
    }
    
}

extension Collection where Iterator.Element == OptionSet {
    
    func reduced<T: OptionSet>() -> T {
        return reduce(T()) {
            var newResult = $0
            newResult.insert($1)
            return newResult
        }
    }
    
}

extension Collection where Iterator.Element == OptionSet {
    func reduced() -> Iterator.Element {
        return Iterator.Element(self)
    }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
    return options.reduce(T()) {
        var newResult = $0
        newResult.insert($1)
        
        return newResult
    }
}

Jon Shier


(Erica Sadun) #2

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

···

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jon Shier) #3

Thanks Erica. I’ve been able to transform arrays of strings into arrays of my OptionSets using an enum approach like you describe. I was looking more for a generic approach that I could apply to all of the various OptionSets I have to decode from JSON. I suppose whether it’s from an array of strings or array of the OptionSet is less important, but getting to the array of the OptionSet itself is something I can already do.

Thanks,

Jon

···

On Nov 3, 2016, at 9:37 PM, Erica Sadun <erica@ericasadun.com> wrote:

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Fritz Anderson) #4

I’m curious about relying on the hash value of an enum case being its declaration-order index. A sage (http://ericasadun.com/2015/07/12/swift-enumerations-or-how-to-annoy-tom/) warns that this is an implementation detail. I haven’t seen anything saying it is API. Has it been resolved?

It’s the most plausible implementation, but I’d think code that relies on case order would break silently (likely at widely-separated locations) if a case were inserted or removed. That suggests to me it’s not possible to regularize this behavior.

Folkloric API (like SEL :left_right_arrow:︎ char* in ObjC) makes me itch.

  — F

···

On 3 Nov 2016, at 8:37 PM, Erica Sadun via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }


(Erica Sadun) #5

Like this?

let sets: [MyOptionSet] = [MyOptionSet(strings: ["one"]), MyOptionSet(strings: ["two"]), MyOptionSet(strings: ["one", "two"])]
let unioned = sets.reduce(MyOptionSet(rawValue: 0)) {
    (result, set) in return result.union(set)
}
unioned.rawValue

···

On Nov 3, 2016, at 7:44 PM, Jon Shier <jon@jonshier.com> wrote:

Thanks Erica. I’ve been able to transform arrays of strings into arrays of my OptionSets using an enum approach like you describe. I was looking more for a generic approach that I could apply to all of the various OptionSets I have to decode from JSON. I suppose whether it’s from an array of strings or array of the OptionSet is less important, but getting to the array of the OptionSet itself is something I can already do.

Thanks,

Jon

On Nov 3, 2016, at 9:37 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Erica Sadun) #6

How about

func joinOptionSets<OS: OptionSet>(_ sets: [OS]) -> OS {
    return sets.reduce([] as OS) {
        (result, set) in return result.union(set)
    }
}

joinOptionSets(sets).rawValue

-- E

···

On Nov 3, 2016, at 7:48 PM, Erica Sadun via swift-users <swift-users@swift.org> wrote:

Like this?

let sets: [MyOptionSet] = [MyOptionSet(strings: ["one"]), MyOptionSet(strings: ["two"]), MyOptionSet(strings: ["one", "two"])]
let unioned = sets.reduce(MyOptionSet(rawValue: 0)) {
    (result, set) in return result.union(set)
}
unioned.rawValue

On Nov 3, 2016, at 7:44 PM, Jon Shier <jon@jonshier.com <mailto:jon@jonshier.com>> wrote:

Thanks Erica. I’ve been able to transform arrays of strings into arrays of my OptionSets using an enum approach like you describe. I was looking more for a generic approach that I could apply to all of the various OptionSets I have to decode from JSON. I suppose whether it’s from an array of strings or array of the OptionSet is less important, but getting to the array of the OptionSet itself is something I can already do.

Thanks,

Jon

On Nov 3, 2016, at 9:37 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users


(Jon Shier) #7

Yes, just in a generic fashion. I don’t have so many OptionSets to decode that writing the typed reduce code over and over again is terrible, I just hoped there would be a way to write it generically. I just can’t seem to get the types to work out. I’m just missing the final step, generically reducing an array of OptionSet values to a single OptionSet value.

Jon

···

On Nov 3, 2016, at 9:48 PM, Erica Sadun <erica@ericasadun.com> wrote:

Like this?

let sets: [MyOptionSet] = [MyOptionSet(strings: ["one"]), MyOptionSet(strings: ["two"]), MyOptionSet(strings: ["one", "two"])]
let unioned = sets.reduce(MyOptionSet(rawValue: 0)) {
    (result, set) in return result.union(set)
}
unioned.rawValue

On Nov 3, 2016, at 7:44 PM, Jon Shier <jon@jonshier.com <mailto:jon@jonshier.com>> wrote:

Thanks Erica. I’ve been able to transform arrays of strings into arrays of my OptionSets using an enum approach like you describe. I was looking more for a generic approach that I could apply to all of the various OptionSets I have to decode from JSON. I suppose whether it’s from an array of strings or array of the OptionSet is less important, but getting to the array of the OptionSet itself is something I can already do.

Thanks,

Jon

On Nov 3, 2016, at 9:37 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Jon Shier) #8

Yes indeed! Apparently union works with the generic but insert did not. Strange. Anyway, I ended up here:

func reducedOptions<T: OptionSet>(_ options: [T]) -> T {
    return options.reduce(T()) { return $0.union($1) }
}

Thanks!

Jon

···

On Nov 3, 2016, at 9:56 PM, Erica Sadun <erica@ericasadun.com> wrote:

How about

func joinOptionSets<OS: OptionSet>(_ sets: [OS]) -> OS {
    return sets.reduce([] as OS) {
        (result, set) in return result.union(set)
    }
}

joinOptionSets(sets).rawValue

-- E

On Nov 3, 2016, at 7:48 PM, Erica Sadun via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Like this?

let sets: [MyOptionSet] = [MyOptionSet(strings: ["one"]), MyOptionSet(strings: ["two"]), MyOptionSet(strings: ["one", "two"])]
let unioned = sets.reduce(MyOptionSet(rawValue: 0)) {
    (result, set) in return result.union(set)
}
unioned.rawValue

On Nov 3, 2016, at 7:44 PM, Jon Shier <jon@jonshier.com <mailto:jon@jonshier.com>> wrote:

Thanks Erica. I’ve been able to transform arrays of strings into arrays of my OptionSets using an enum approach like you describe. I was looking more for a generic approach that I could apply to all of the various OptionSets I have to decode from JSON. I suppose whether it’s from an array of strings or array of the OptionSet is less important, but getting to the array of the OptionSet itself is something I can already do.

Thanks,

Jon

On Nov 3, 2016, at 9:37 PM, Erica Sadun <erica@ericasadun.com <mailto:erica@ericasadun.com>> wrote:

Maybe something like this? Or you could just bitwise || individual sets. Or you could use a dictionary to lookup [string: rawValue]. etc.

public struct MyOptionSet: OptionSet {
    public static let one = MyOptionSet(rawValue: 1 << 0)
    public static let two = MyOptionSet(rawValue: 1 << 1)
    public static let three = MyOptionSet(rawValue: 1 << 2)
    
    public var rawValue: Int { return _rawValue }
    public init(rawValue: Int) { self._rawValue = rawValue }
    private let _rawValue: Int
    
    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }
}

let stringArray: [String] = ["one", "three"]
let stringOptions = MyOptionSet(strings: stringArray)
stringOptions.rawValue

On Nov 3, 2016, at 7:09 PM, Jon Shier via swift-users <swift-users@swift.org <mailto:swift-users@swift.org>> wrote:

Swifters:
  I’m dealing with a JSON API where sets of options are returned as arrays of strings. Representing these as OptionSets seems ideal. I can decode the arrays of strings into an array of individual OptionSet values, but I’ve run into a dead end when trying generically reduce the array of OptionSets to a single OptionSet value. I’ve tried variety of ways of definition a Collection extension, even tried defining a global function, but I can’t seem to use the OptionSet sequence initializer or reduce itself (cannot invoke insert with argument of type (OptionSet) (or T)). Any guidance here?
  Here’s what I’ve tried:

extension Collection where Iterator.Element == OptionSet {

   func reduced() -> Iterator.Element {
       return reduce(Iterator.Element()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {

   func reduced<T: OptionSet>() -> T {
       return reduce(T()) {
           var newResult = $0
           newResult.insert($1)
           return newResult
       }
   }

}

extension Collection where Iterator.Element == OptionSet {
   func reduced() -> Iterator.Element {
       return Iterator.Element(self)
   }
}

func reduced<T: OptionSet>(_ options: [T]) -> T {
   return options.reduce(T()) {
       var newResult = $0
       newResult.insert($1)

       return newResult
   }
}

Jon Shier
_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org <mailto:swift-users@swift.org>
https://lists.swift.org/mailman/listinfo/swift-users


(Erica Sadun) #9

It is absolutely an implementation detail and one you should never rely upon!

— Erica

···

Sent from my iPhone

On Nov 4, 2016, at 2:17 PM, Fritz Anderson <fritza@manoverboard.org> wrote:

On 3 Nov 2016, at 8:37 PM, Erica Sadun via swift-users <swift-users@swift.org> wrote:

    private enum StringEnum: String { case one, two, three }
    public init(strings: [String]) {
        var set = MyOptionSet()
        strings.flatMap({ StringEnum(rawValue: $0) })
            .flatMap({ MyOptionSet(rawValue: 1 << $0.hashValue) })
            .forEach { set.insert($0) }
        _rawValue = set.rawValue
    }

I’m curious about relying on the hash value of an enum case being its declaration-order index. A sage (http://ericasadun.com/2015/07/12/swift-enumerations-or-how-to-annoy-tom/) warns that this is an implementation detail. I haven’t seen anything saying it is API. Has it been resolved?

It’s the most plausible implementation, but I’d think code that relies on case order would break silently (likely at widely-separated locations) if a case were inserted or removed. That suggests to me it’s not possible to regularize this behavior.

Folkloric API (like SEL :left_right_arrow:︎ char* in ObjC) makes me itch.

  — F