List of all Enum values (for simple enums)


(Jacob Bandes-Storch) #1

Enums are often used without associated values:

    enum Attribute { case Title, Date }
    enum Style { case Dark, Light }

In such cases, it's very useful to be able to iterate over all possible
values. But you have to do it manually:

    extension Attribute {
        static var allValues: [Attribute] {
            return [.Title, .Date] // imagine this x100, and not
autogenerated :frowning:
        }
    }

It would be nice if the compiler generated this for us. It doesn't have to
be an Array, but any kind of SequenceType. Maybe something like
"StaticCollection". Of course, this doesn't work in the general case, but I
think simple enums are common enough that it might be worth doing.

Thoughts?

Jacob Bandes-Storch


(Chris Lattner) #2

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris

···

On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org> wrote:

Enums are often used without associated values:

    enum Attribute { case Title, Date }
    enum Style { case Dark, Light }

In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:

    extension Attribute {
        static var allValues: [Attribute] {
            return [.Title, .Date] // imagine this x100, and not autogenerated :(
        }
    }

It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.


(Brent Royal-Gordon) #3

    extension Attribute {
        static var allValues: [Attribute] {
            return [.Title, .Date] // imagine this x100, and not autogenerated :frowning:
        }
    }

It would be nice if the compiler generated this for us.

You know, I was thinking about this the other day when the topic of numeric minimum/maximums came up.

In some sense these are related ideas. These types have in common that they have a particular finite, easily-calculated set of possible values, and it’s convenient to be able to look at that set in various ways. This has the feel of a protocol:

  protocol Enumerable {
    typealias Enumeration: SequenceType where Generator.Element == Self
    var allValues: Enumeration
  }

For a simple enum, `Enumeration` would be something like an `Array` or `Set`, and `allValues` would primarily be iterated over; for an integer type, `Enumeration` would be a range and `allValues` would primarily have its `first` and `last` elements examined. (Well, there’s a problem with using a range. A `Range<T: IntegerType>` can never include `T.max`, because then its `endIndex` would have to be `T.max + 1`, which is by definition not representable in `T`. But you could imagine a range-like type without this limitation.) However, in each case there are some fairly useless operations exposed by `allValues`, and I’m not sure if I like that.

One interesting thing I noticed: enums with associated values could also be made `Enumerable`, as long as all associated values are `Enumerable` and the enum is not recursive. For instance:

  enum Foo {
    case Alice, Bob
  }
  enum Bar {
    case Charlie (Foo), Eve (Foo, Foo)
  }
  Bar.allValues // => [ .Charlie(.Alice), .Charlie(.Bob), .Eve(.Alice, .Alice), .Eve(.Alice, .Bob), .Eve(.Bob, .Alice), .Eve(.Bob, .Bob) ]

This is even in principle true of associated values of type `Int`, although obviously the set of possible values for `Int` would be so large that it would have to be generated lazily (not to mention that I can’t see much practical use for it). This would also imply that `Optional<T: Enumerable>` would be `Enumerable`, with an `allValues` consisting basically of `[.None] + Wrapped.all.map(.Some)`.

Anyway, I’m not sure if what I’m describing here is a good idea. It might be overcomplicating things, and some parts of it would probably be difficult to implement. But I thought it was an interesting observation.

···

--
Brent Royal-Gordon
Architechies


(Brent Royal-Gordon) #4

  protocol Enumerable {
    typealias Enumeration: SequenceType where Generator.Element == Self
    var allValues: Enumeration
  }

Er, that should have been `static var`, of course. That was bright of me.

···

--
Brent Royal-Gordon
Architechies


(Kevin Wooten) #5

I don’t think this is overcomplicating things at all. I see many useful cases for this.

I would suggest a simple change to Enumerable…

protocol Enumerable : CustomStringConvertible, CustomDebugStringConvertible {
    …
}

The number of times the enumeration value name is needed at runtime is just too great.

···

On Dec 9, 2015, at 5:05 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

   extension Attribute {
       static var allValues: [Attribute] {
           return [.Title, .Date] // imagine this x100, and not autogenerated :frowning:
       }
   }

It would be nice if the compiler generated this for us.

You know, I was thinking about this the other day when the topic of numeric minimum/maximums came up.

In some sense these are related ideas. These types have in common that they have a particular finite, easily-calculated set of possible values, and it’s convenient to be able to look at that set in various ways. This has the feel of a protocol:

  protocol Enumerable {
    typealias Enumeration: SequenceType where Generator.Element == Self
    var allValues: Enumeration
  }

For a simple enum, `Enumeration` would be something like an `Array` or `Set`, and `allValues` would primarily be iterated over; for an integer type, `Enumeration` would be a range and `allValues` would primarily have its `first` and `last` elements examined. (Well, there’s a problem with using a range. A `Range<T: IntegerType>` can never include `T.max`, because then its `endIndex` would have to be `T.max + 1`, which is by definition not representable in `T`. But you could imagine a range-like type without this limitation.) However, in each case there are some fairly useless operations exposed by `allValues`, and I’m not sure if I like that.

One interesting thing I noticed: enums with associated values could also be made `Enumerable`, as long as all associated values are `Enumerable` and the enum is not recursive. For instance:

  enum Foo {
    case Alice, Bob
  }
  enum Bar {
    case Charlie (Foo), Eve (Foo, Foo)
  }
  Bar.allValues // => [ .Charlie(.Alice), .Charlie(.Bob), .Eve(.Alice, .Alice), .Eve(.Alice, .Bob), .Eve(.Bob, .Alice), .Eve(.Bob, .Bob) ]

This is even in principle true of associated values of type `Int`, although obviously the set of possible values for `Int` would be so large that it would have to be generated lazily (not to mention that I can’t see much practical use for it). This would also imply that `Optional<T: Enumerable>` would be `Enumerable`, with an `allValues` consisting basically of `[.None] + Wrapped.all.map(.Some)`.

Anyway, I’m not sure if what I’m describing here is a good idea. It might be overcomplicating things, and some parts of it would probably be difficult to implement. But I thought it was an interesting observation.

--
Brent Royal-Gordon
Architechies

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


(Jacob Bandes-Storch) #6

Do you have any recommendations for where in the compiler this would
happen, for those of us without thorough knowledge of all parts? What would
the team need to see in a proposal for it to be sufficiently complete?

···

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution < > swift-evolution@swift.org> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible
values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not
autogenerated :frowning:
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have
to be an Array, but any kind of SequenceType. Maybe something like
"StaticCollection". Of course, this doesn't work in the general case, but I
think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the
ability to do this somehow. Similarly, for integer-backed enums, many
people want to be able to know the “max” enum rawValue so they can index
into them.

-Chris


(Chris Lattner) #7

Do you have any recommendations for where in the compiler this would happen, for those of us without thorough knowledge of all parts? What would the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise initializers on structs. That said, I think that hashing out the right user model and set of capabilities is the first place to start.

-Chris

···

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not autogenerated :(
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris


(Joe Groff) #8

Everything is string-convertible; no need to force Enumerable implementations to provide custom printing implementations.

-Joe

···

On Dec 9, 2015, at 4:37 AM, Kevin Wooten via swift-evolution <swift-evolution@swift.org> wrote:

I don’t think this is overcomplicating things at all. I see many useful cases for this.

I would suggest a simple change to Enumerable…

protocol Enumerable : CustomStringConvertible, CustomDebugStringConvertible {
   …
}

The number of times the enumeration value name is needed at runtime is just too great.


(David Waite) #9

There are a number of possible proposals for enhancements I see off the bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and Streamable might make sense as well. You would likely want CustomDebugStringConvertible to also be defined to supply the original type-based value.

-DW

···

On Dec 8, 2015, at 11:13 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Do you have any recommendations for where in the compiler this would happen, for those of us without thorough knowledge of all parts? What would the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise initializers on structs. That said, I think that hashing out the right user model and set of capabilities is the first place to start.

-Chris

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not autogenerated :frowning:
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris

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


(Jacob Bandes-Storch) #10

Would this work with enums imported from C/Obj-C code as well? Personally,
I've worked with code that would benefit greatly from it. But I could
imagine confusion if a C enum already defines "max" or "number of elements"
as a member of the enum, and Swift imports .max as being one greater.

Jacob

···

On Wed, Dec 9, 2015 at 10:19 AM, David Waite <david@alkaline-solutions.com> wrote:

There are a number of possible proposals for enhancements I see off the
bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static
max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and
Streamable might make sense as well. You would likely want
CustomDebugStringConvertible to also be defined to supply the original
type-based value.

-DW

On Dec 8, 2015, at 11:13 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:

Do you have any recommendations for where in the compiler this would
happen, for those of us without thorough knowledge of all parts? What would
the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise
initializers on structs. That said, I think that hashing out the right
user model and set of capabilities is the first place to start.

-Chris

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution < >> swift-evolution@swift.org> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible
values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not
autogenerated :frowning:
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have
to be an Array, but any kind of SequenceType. Maybe something like
"StaticCollection". Of course, this doesn't work in the general case, but I
think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support
the ability to do this somehow. Similarly, for integer-backed enums, many
people want to be able to know the “max” enum rawValue so they can index
into them.

-Chris

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


(David Waite) #11

Per my email on this thread, the one case which might be worth handling is enums with String raw values. However, a String-backed enum is not necessarily the same as in other languages where annotations/attributes are used to indicate a representation name for the enumerated value, so this would likely need to be a behavior one could either opt into or out of.

-DW

···

On Dec 9, 2015, at 12:06 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

The number of times the enumeration value name is needed at runtime is just too great.

Everything is string-convertible; no need to force Enumerable implementations to provide custom printing implementations.


(Chris Lattner) #12

There are a number of possible proposals for enhancements I see off the bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and Streamable might make sense as well. You would likely want CustomDebugStringConvertible to also be defined to supply the original type-based value.

Another design point to consider: instead of making *every* enum generate the “allValues” capability, it might make sense to restrict this synthesization to enums that opt into it by conforming to a protocol. Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff automatically generated.

-Chris

···

On Dec 9, 2015, at 10:19 AM, David Waite <david@alkaline-solutions.com> wrote:

-DW

On Dec 8, 2015, at 11:13 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Do you have any recommendations for where in the compiler this would happen, for those of us without thorough knowledge of all parts? What would the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise initializers on structs. That said, I think that hashing out the right user model and set of capabilities is the first place to start.

-Chris

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not autogenerated :(
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris

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


(Kevin Wooten) #13

I know that this currently works...

enum MyEnum { case MyA }
let val = String(MyEnum.MyA) // yields “MyA"

Which I assume is what you are referring to. Although, even after sifting through Swift.String, I am not sure how this support is provided. I assume some magic method is produced by the compiler for enums.

In the generics of today, auto generated functions like these do not seem to be available to generic implementations. So what I was trying to achieve by adding the string convertible protocol was to ensure the availability of code like this…

parseFromSource<E: Enumerable>(source: Source) -> E? {
  let str = source.readString()
  for e in E.allValues {
    if (e.description == str) {
      return e;
    }
  }
  return nil;
}

From what I know of the generics implementation if we tried to replace the “e.description == str” with “String(e) == str” it would fail; since that initializer is not formalized anywhere in the Enumerable protocol.

Another option entirely would be to just always produce an initializer similar to the raw value string enum initializer that will match raw values. Essentially a magic method similar to the one I wrote above but for all enums. Although the code above is much more flexible even beyond my simple parsing example.

···

On Dec 9, 2015, at 12:06 PM, Joe Groff <jgroff@apple.com> wrote:

On Dec 9, 2015, at 4:37 AM, Kevin Wooten via swift-evolution <swift-evolution@swift.org> wrote:

I don’t think this is overcomplicating things at all. I see many useful cases for this.

I would suggest a simple change to Enumerable…

protocol Enumerable : CustomStringConvertible, CustomDebugStringConvertible {
  …
}

The number of times the enumeration value name is needed at runtime is just too great.

Everything is string-convertible; no need to force Enumerable implementations to provide custom printing implementations.

-Joe


(Jacob Bandes-Storch) #14

And I suppose it would have to be possible to add this conformance to a
pre-existing type? You'd want to be able to do "extension NSTextAlignment
: Enumerable {}". But I'm not sure if it would work well to generate this
on-demand; might work better to do it at interface-generation time, along
with OptionSetType conformances, etc.

Jacob

···

On Wed, Dec 9, 2015 at 5:05 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 9, 2015, at 10:19 AM, David Waite <david@alkaline-solutions.com> > wrote:

There are a number of possible proposals for enhancements I see off the
bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static
max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and
Streamable might make sense as well. You would likely want
CustomDebugStringConvertible to also be defined to supply the original
type-based value.

Another design point to consider: instead of making *every* enum generate
the “allValues” capability, it might make sense to restrict this
synthesization to enums that opt into it by conforming to a protocol.
Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff
automatically generated.

-Chris


(Joe Groff) #15

String(e) is defined for all types; there's an unconstrained String.init<T>(_: T) method. It's implemented using runtime reflection. You should use the String(x) initializer, or the equivalent interpolation "\(x)", instead of using .description directly.

-Joe

···

On Dec 9, 2015, at 8:21 PM, Kevin Wooten <kdubb@me.com> wrote:

I know that this currently works...

enum MyEnum { case MyA }
let val = String(MyEnum.MyA) // yields “MyA"

Which I assume is what you are referring to. Although, even after sifting through Swift.String, I am not sure how this support is provided. I assume some magic method is produced by the compiler for enums.

In the generics of today, auto generated functions like these do not seem to be available to generic implementations. So what I was trying to achieve by adding the string convertible protocol was to ensure the availability of code like this…

parseFromSource<E: Enumerable>(source: Source) -> E? {
  let str = source.readString()
  for e in E.allValues {
    if (e.description == str) {
      return e;
    }
  }
  return nil;
}

From what I know of the generics implementation if we tried to replace the “e.description == str” with “String(e) == str” it would fail; since that initializer is not formalized anywhere in the Enumerable protocol.


(Slava Pestov) #16

Another design point to consider: instead of making *every* enum generate the “allValues” capability, it might make sense to restrict this synthesization to enums that opt into it by conforming to a protocol. Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff automatically generated.

-Chris

The necessary information for getting enum case names (with and without payloads) is already emitted by IRGen as part of type metadata, but the runtime reflection interface for accessing it does not support this use-case (introspecting a type without a value) and in general is a bit heavy weight.

In the past we’ve talked about switching to an “opt-in” reflection model, where protocol conformance signals that metadata generation should occur. If we combine this with a nice type reflection interface, the original poster’s use-case should be taken care of well, I think.

Slava

···

On Dec 9, 2015, at 5:05 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

-DW

On Dec 8, 2015, at 11:13 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Do you have any recommendations for where in the compiler this would happen, for those of us without thorough knowledge of all parts? What would the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise initializers on structs. That said, I think that hashing out the right user model and set of capabilities is the first place to start.

-Chris

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not autogenerated :frowning:
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris

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

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


(Chris Lattner) #17

There are a number of possible proposals for enhancements I see off the bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and Streamable might make sense as well. You would likely want CustomDebugStringConvertible to also be defined to supply the original type-based value.

Another design point to consider: instead of making *every* enum generate the “allValues” capability, it might make sense to restrict this synthesization to enums that opt into it by conforming to a protocol. Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff automatically generated.

-Chris

And I suppose it would have to be possible to add this conformance to a pre-existing type? You'd want to be able to do "extension NSTextAlignment : Enumerable {}”.

Yes, exactly. This would allow it to work with C types as you suggest, as well as providing the ability to retroactively provide it for Swift enums that didn’t anticipate the need.

But I'm not sure if it would work well to generate this on-demand; might work better to do it at interface-generation time, along with OptionSetType conformances, etc.

I’m not sure what you mean here,

-Chris

···

On Dec 9, 2015, at 5:24 PM, Jacob Bandes-Storch <jtbandes@gmail.com> wrote:
On Wed, Dec 9, 2015 at 5:05 PM, Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

On Dec 9, 2015, at 10:19 AM, David Waite <david@alkaline-solutions.com <mailto:david@alkaline-solutions.com>> wrote:


(Zef Houssney) #18

Yes I agree this would be great! I think an opt-in design where you can extend existing enums to conform is awesome.

As a suggestion for the names of the methods, I think the following would be great:

enum Thing: String, Enumerable {
    case One, Two, Three
}

// available for any conforming enum:
Thing.cases // returns [Thing] = [.One, .Two, .Three]

// only available for enums with raw values:
Thing.rawValues // returns [String] = ["One", "Two", "Three"]
Regarding a name for the protocol, perhaps “Introspectable” or “Listable”?

Lastly, for enums that have cases with Associated Values, that definitely seems more complex and may be best suited for a separate discussion. I’d much rather see the “simple” version above implemented first, followed by something that deals with enums that have associated values in a later release. However, I do have a suggestion that’s different from what Brent suggested, which is that instead of returning actual enum values, I could see returning the functions associated with them as being potentially useful. I can show an example of what this might look like if anyone is interested.

···

On Dec 10, 2015, at 9:37 PM, Slava Pestov via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 9, 2015, at 5:05 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Another design point to consider: instead of making *every* enum generate the “allValues” capability, it might make sense to restrict this synthesization to enums that opt into it by conforming to a protocol. Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff automatically generated.

-Chris

The necessary information for getting enum case names (with and without payloads) is already emitted by IRGen as part of type metadata, but the runtime reflection interface for accessing it does not support this use-case (introspecting a type without a value) and in general is a bit heavy weight.

In the past we’ve talked about switching to an “opt-in” reflection model, where protocol conformance signals that metadata generation should occur. If we combine this with a nice type reflection interface, the original poster’s use-case should be taken care of well, I think.

Slava

-DW

On Dec 8, 2015, at 11:13 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 8, 2015, at 10:09 PM, Jacob Bandes-Storch <jtbandes@gmail.com <mailto:jtbandes@gmail.com>> wrote:

Do you have any recommendations for where in the compiler this would happen, for those of us without thorough knowledge of all parts? What would the team need to see in a proposal for it to be sufficiently complete?

This would slot into the same logic that synthesizes memberwise initializers on structs. That said, I think that hashing out the right user model and set of capabilities is the first place to start.

-Chris

On Tue, Dec 8, 2015 at 10:05 PM Chris Lattner <clattner@apple.com <mailto:clattner@apple.com>> wrote:

> On Dec 8, 2015, at 9:53 PM, Jacob Bandes-Storch via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
> Enums are often used without associated values:
>
> enum Attribute { case Title, Date }
> enum Style { case Dark, Light }
>
> In such cases, it's very useful to be able to iterate over all possible values. But you have to do it manually:
>
> extension Attribute {
> static var allValues: [Attribute] {
> return [.Title, .Date] // imagine this x100, and not autogenerated :frowning:
> }
> }
>
> It would be nice if the compiler generated this for us. It doesn't have to be an Array, but any kind of SequenceType. Maybe something like "StaticCollection". Of course, this doesn't work in the general case, but I think simple enums are common enough that it might be worth doing.

This is a commonly requested feature, and tons of people would support the ability to do this somehow. Similarly, for integer-backed enums, many people want to be able to know the “max” enum rawValue so they can index into them.

-Chris

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

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

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


(Jacob Bandes-Storch) #19

I'd have to look at the code before I'll be able to ask a fully coherent
question (you mentioned the same place memberwise initializers are
synthesized).

I was guessing that having multiple "extension NSSortOptions : Enumerable
{}" in different modules (or different files in the same module) might
cause problems, so you'd have to do it only one place — i.e. NSSortOptions
would either be imported as protocol<OptionSetType, Enumerable> or it
wouldn't, with no way to change it post-hoc from user code.

···

On Wed, Dec 9, 2015 at 5:26 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 9, 2015, at 5:24 PM, Jacob Bandes-Storch <jtbandes@gmail.com> > wrote:

On Wed, Dec 9, 2015 at 5:05 PM, Chris Lattner <clattner@apple.com> wrote:

On Dec 9, 2015, at 10:19 AM, David Waite <david@alkaline-solutions.com> >> wrote:

There are a number of possible proposals for enhancements I see off the
bat for “basic" enums (without associated data):

1. A generated implementation of SequenceType based on declaration order
2. A second interface or extension to the enum type could supply static
max and min properties when the RawValue is Comparable
3. For enums with a String raw value, CustomStringConvertible and
Streamable might make sense as well. You would likely want
CustomDebugStringConvertible to also be defined to supply the original
type-based value.

Another design point to consider: instead of making *every* enum generate
the “allValues” capability, it might make sense to restrict this
synthesization to enums that opt into it by conforming to a protocol.
Intentionally not the right protocol name, but perhaps:

enum X { A, B } // not enumerable.
enum X : Enumerable { A, B } // has allValues and other stuff
automatically generated.

-Chris

And I suppose it would have to be possible to add this conformance to a
pre-existing type? You'd want to be able to do "extension NSTextAlignment
: Enumerable {}”.

Yes, exactly. This would allow it to work with C types as you suggest, as
well as providing the ability to retroactively provide it for Swift enums
that didn’t anticipate the need.

But I'm not sure if it would work well to generate this on-demand; might
work better to do it at interface-generation time, along with OptionSetType
conformances, etc.

I’m not sure what you mean here,

-Chris


(Brent Royal-Gordon) #20

However, I do have a suggestion that’s different from what Brent suggested, which is that instead of returning actual enum values, I could see returning the functions associated with them as being potentially useful. I can show an example of what this might look like if anyone is interested.

Interesting. The problem I see with this is that, if by “the functions associated with them” you mean their constructors, each constructor would have a different set of parameters. To distinguish between them, you would probably need…an enum.

On the other hand, if you mean “functions testing an instance of the enum against that case, and returning true if it matches”, that’s a more interesting possibility.

···

--
Brent Royal-Gordon
Architechies