[swift-evolution] Pre-proposal: CaseEnumerable protocol (derived collection of enum cases)

David Sweeris davesweeris at mac.com
Wed Jan 20 17:13:51 CST 2016


If the associated values are all enums themselves, that's great. What if your enum is an error type, and the associated values are all strings with maybe diagnostic info or time stamps or something?

If Swift’s stdlib had a protocol (either `Initable` or `HasDefaultValue`, as used below), and the language had better support for generic tuple processing:
Tuples automatically conform to any protocol to which all its members conform.
Mapping over a tuple’s member’s types: let x = (Int, String, Double).map { $0.init() } // returns (Int.init(), String.init(), Double.init())
Mapping over a tuple’s members: let x = (0, “”, 0.0).map { $0.hashValue } // returns (0.hashValue, “”.hashValue, 0.0.hashValue)
Subscripting tuple’s: (0, “”, 0.0)[0] 
The ability to append/appendElements to tuples, such that if T = (Int, Int), U = (Double, Double), then ().appendElements(T,U).append(NSFileManager) would equal (Int, Int, Double, Double, NSFileManager) 
Then I think we’d only need a couple more features:
An implicit typealias in enums, which is a tuple of all the cases’ associated value’s type
The ability to restrict a protocol to only be conformable by enums, like we can already do with classes

and I think we’d get all this for free with a couple protocols:

protocol Initable { init() }
protocol HasDefaultValue {
    typealias DefaultValue
    static var defaultValue: DefaultValue {get}
}
extension HasDefaultValue where Self: Initable, DefaultValue == Self {
    static var defaultValue: DefaultValue { return Self.init() } // can be overridden if not appropriate
}
protocol FiniteEnumerable : enum, HasDefaultValue {
    typealias AssociatedValues // A tuple of the associated type for each case
    typealias DefaultValue
    static var defaultValues: DefaultValue {get}
    static var cases: [Self] {get}
}

extension FiniteEnumerable {
    static var count: Int { return Int(Mirror(reflecting: self.defaultValues).children.count) }
}
extension FiniteEnumerable where AssociatedValues: HasDefaultValue, DefaultValue == AssociatedValues.DefaultValue {
    static var defaultValues: DefaultValue { return AssociatedValues.defaultValue }
}
extension FiniteEnumerable where AssociatedValues: FiniteEnumerable, DefaultValue == [Self] {
    static var defaultValues: DefaultValue {
        var allCases = ()
        for i in 0 ..< Self.cases.count {
            for assocValue in AssociatedValues.cases[i] {
                allCases.append(theCase(assocValue)) // FWIW, this line and the “FiniteEnumerable : enum” parts are the only two errors Xcode can find.
            }
        }
        return allCases
    } // Over
}

Hmm… I may have gotten `defaultValues` and `cases` switched around in there. But the point is that they all could be added through protocol extensions, which have the advantage of:
1) provides default declarations
2) that are overridable if you don’t like them
3) it’ll throw a compile-time nonconformance error if there’s a hole in the protocol extensions
4) less magic.

- Dave Sweeris

On Jan 20, 2016, at 10:04, Joe Groff via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:

> 
>> On Jan 20, 2016, at 9:01 AM, Jacob Bandes-Storch via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> I've been thinking about naming a bit. I'm worried that "values" / "allValues" won't make sense if this feature eventually goes in the direction of returning type constructors. For enums with associated types, the cases may actually be functions taking the associated type and returning the enum type. (There's an example under "Future directions" in the proposal). Calling these "values" seems strange to me, but calling them "cases" makes sense.
> 
> That seems like a fairly specialized use case to me. I'd expect the default behavior for enums with associated values to enumerate all possible values of each case (whose associated values would themselves need to be ValueEnumerable), not the case constructors themselves. That's more generally useful when using associated values to categorize constants.
> 
> -Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160120/d1267957/attachment.html>


More information about the swift-evolution mailing list