Request: Ability to refer to an enum case in abstract (without its associated value)

I'm not sure if this is what you're driving at, but I've found a use-case for the ability to refer to an enum case generically without reference to any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different screens to which the user can navigate. (A screen in our case usually means a view controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render their content, some of our enum cases have associated values to store the required view model objects.

This allows an enum value to contain all the information needed to present any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to refer to a screen in the abstract and be able to 'switch' against it without any associated values. (This would allow me to be able to refer to, say, "the User Account screen" in the abstract, whereas now I can only refer to "the User Account screen displaying details for this particular user".)

We've identified two possible solutions to this issue and have implemented one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names but without any associated values. These parallel structures need to be manually maintained, which is something the compiler cannot enforce.

• Another option involves removing the associated values from the enum and passing around objects to contain the necessary view model objects. At various points, we assert that the view model container object is of the expected type for the enum case, but again, that now moves to runtime an error that otherwise would've been caught by the compiler.

¡¡¡

---

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

FWIW, as long as we’re asking for some compiler assistance generating useful enumeration-related boilerplate, I’d like to request that something along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

1 Like

I'm not sure if this is what you're driving at, but I've found a use-case for the ability to refer to an enum case generically without reference to any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different screens to which the user can navigate. (A screen in our case usually means a view controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render their content, some of our enum cases have associated values to store the required view model objects.

This allows an enum value to contain all the information needed to present any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to refer to a screen in the abstract and be able to 'switch' against it without any associated values. (This would allow me to be able to refer to, say, "the User Account screen" in the abstract, whereas now I can only refer to "the User Account screen displaying details for this particular user".)

I might be missing something, but you can do this already. 'case .CaseWithPayload:' matches any CaseWithPayload regardless of its payload.

-Joe

¡¡¡

On Dec 10, 2015, at 2:05 PM, Evan Maloney via swift-evolution <swift-evolution@swift.org> wrote:

We've identified two possible solutions to this issue and have implemented one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names but without any associated values. These parallel structures need to be manually maintained, which is something the compiler cannot enforce.

• Another option involves removing the associated values from the enum and passing around objects to contain the necessary view model objects. At various points, we assert that the view model container object is of the expected type for the enum case, but again, that now moves to runtime an error that otherwise would've been caught by the compiler.

---

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

FWIW, as long as we’re asking for some compiler assistance generating useful enumeration-related boilerplate, I’d like to request that something along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

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

//Swift version 2.2-dev
enum case 'CaseWithPayload' not found

¡¡¡

On Thu, Dec 10, 2015 at 3:31 PM, Joe Groff via swift-evolution < swift-evolution@swift.org> wrote:

On Dec 10, 2015, at 2:05 PM, Evan Maloney via swift-evolution < > swift-evolution@swift.org> wrote:

I'm not sure if this is what you're driving at, but I've found a use-case
for the ability to refer to an enum case generically without reference to
any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different *screens* to
which the user can navigate. (A *screen* in our case usually means a view
controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render
their content, some of our enum cases have associated values to store the
required view model objects.

This allows an enum value to contain all the information needed to present
any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to
refer to a screen in the abstract and be able to 'switch' against it
without any associated values. (This would allow me to be able to refer to,
say, "the User Account screen" in the abstract, whereas now I can only
refer to "the User Account screen displaying details for this particular
user".)

I might be missing something, but you can do this already. 'case
.CaseWithPayload:' matches any CaseWithPayload regardless of its payload.

-Joe

We've identified two possible solutions to this issue and have implemented
one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names
but without any associated values. These parallel structures need to be
manually maintained, which is something the compiler cannot enforce.

• Another option involves removing the associated values from the enum and
passing around objects to contain the necessary view model objects. At
various points, we assert that the view model container object is of the
expected type for the enum case, but again, that now moves to runtime an
error that otherwise would've been caught by the compiler.

---

When an enum case takes one or more associated values, it acts more like a
*type* than a *value* because it specifies a format for storing
information without specifying the exact informations stored. We're able to
refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a
parallel representation containing the same cases but without associated
values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but
that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution < > swift-evolution@swift.org> wrote:

FWIW, as long as we’re asking for some compiler assistance generating
useful enumeration-related boilerplate, I’d like to request that something
along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

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

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

I'm not sure if this is what you're driving at, but I've found a use-case for the ability to refer to an enum case generically without reference to any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different screens to which the user can navigate. (A screen in our case usually means a view controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render their content, some of our enum cases have associated values to store the required view model objects.

This allows an enum value to contain all the information needed to present any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to refer to a screen in the abstract and be able to 'switch' against it without any associated values. (This would allow me to be able to refer to, say, "the User Account screen" in the abstract, whereas now I can only refer to "the User Account screen displaying details for this particular user".)

We've identified two possible solutions to this issue and have implemented one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names but without any associated values. These parallel structures need to be manually maintained, which is something the compiler cannot enforce.

^ this is what I have been doing by hand when needed (mainly to support serialization); as you say, the compiler doesn’t do anything enforce the two "parallel enums" stay in sync with each other.

• Another option involves removing the associated values from the enum and passing around objects to contain the necessary view model objects. At various points, we assert that the view model container object is of the expected type for the enum case, but again, that now moves to runtime an error that otherwise would've been caught by the compiler.

^ in your use case I’d probably do something analogous, but even this isn’t necessarily always workable (sometimes multiple cases have the same type of associated value, and aside from *being* a runtime check you risk having the wrong value even if the types match; wouldn’t usually be a risk for view models, but you might have e.g. different “types” of image URLs that need different HTTP headers added to their requests...).

But yes, this is exactly the situation I’m driving at.

If compiler support to synthesize these enums is added I’d prefer it be opt-in, if only to have a natural place in the syntax to customize some of the details (e.g. maybe UInt vs Int, maybe you want @objc on it, and for serialization support starting the “parallel enum” from 1 instead of 0 smooths over a mild annoyance with the `NSCoder` API).

But these are definitely the kinds of things I had in mind.

¡¡¡

On Dec 10, 2015, at 4:05 PM, Evan Maloney <emaloney@gilt.com> wrote:

---

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

FWIW, as long as we’re asking for some compiler assistance generating useful enumeration-related boilerplate, I’d like to request that something along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

Maybe I’m misunderstanding your use case, but I believe what you require is already possible. When switching through enum cases, there’s no obligation to bind to the associated values if they’re not needed.

enum Foo {
  case Bar(String)
  case Baz(Int, Int)
}

let baz = Foo.Baz(1, 2)

switch baz {
case .Bar: print("Bar")
case .Baz: print("Baz")
}

Al

¡¡¡

On 10 Dec 2015, at 22:05, Evan Maloney via swift-evolution <swift-evolution@swift.org> wrote:

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

//Swift version 2.2-dev
enum case 'CaseWithPayload' not found

Sorry, '.CaseWithPayload' was intended as a stand-in for whatever your specific case with payload is named:

enum Foo {
  case A(Int)
  case B
}

let foo = Foo.A(0)

switch foo {
case .A: print("hi")
case .B: print("bye")
}

-Joe

¡¡¡

On Dec 10, 2015, at 5:19 PM, J. Cheyo Jimenez <cheyo@masters3d.com> wrote:

On Thu, Dec 10, 2015 at 3:31 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 10, 2015, at 2:05 PM, Evan Maloney via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'm not sure if this is what you're driving at, but I've found a use-case for the ability to refer to an enum case generically without reference to any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different screens to which the user can navigate. (A screen in our case usually means a view controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render their content, some of our enum cases have associated values to store the required view model objects.

This allows an enum value to contain all the information needed to present any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to refer to a screen in the abstract and be able to 'switch' against it without any associated values. (This would allow me to be able to refer to, say, "the User Account screen" in the abstract, whereas now I can only refer to "the User Account screen displaying details for this particular user".)

I might be missing something, but you can do this already. 'case .CaseWithPayload:' matches any CaseWithPayload regardless of its payload.

-Joe

We've identified two possible solutions to this issue and have implemented one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names but without any associated values. These parallel structures need to be manually maintained, which is something the compiler cannot enforce.

• Another option involves removing the associated values from the enum and passing around objects to contain the necessary view model objects. At various points, we assert that the view model container object is of the expected type for the enum case, but again, that now moves to runtime an error that otherwise would've been caught by the compiler.

---

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

FWIW, as long as we’re asking for some compiler assistance generating useful enumeration-related boilerplate, I’d like to request that something along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

_______________________________________________
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 version 2.2-dev
enum case 'CaseWithPayload' not found

Sorry, '.CaseWithPayload' was intended as a stand-in for whatever your specific case with payload is named:

enum Foo {
  case A(Int)
  case B
}

let foo = Foo.A(0)

switch foo {
case .A: print("hi")
case .B: print("bye")
}

-Joe

This discussion and the ‘List of all enum values’ thread makes me think of a related feature that most people probably aren’t aware of — referring to an enum case constructor for a case with a payload, without actually applying it, yields a function value that you can pass around, eg in the above code ‘Foo.A’ has type Int -> Foo.

In the past we’ve also talked about adding ‘projections’ which test for that enum case and wrap the payload in an optional, where Foo.A would have two overloads, the constructor Int -> Foo and a projection Foo -> Int?.

It might be useful for enum cases to witness protocol requirements, too — has anyone wanted this?

Just food for thought,

Slava

¡¡¡

On Dec 10, 2015, at 5:23 PM, Joe Groff via swift-evolution <swift-evolution@swift.org> wrote:

On Dec 10, 2015, at 5:19 PM, J. Cheyo Jimenez <cheyo@masters3d.com <mailto:cheyo@masters3d.com>> wrote:

On Thu, Dec 10, 2015 at 3:31 PM, Joe Groff via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Dec 10, 2015, at 2:05 PM, Evan Maloney via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'm not sure if this is what you're driving at, but I've found a use-case for the ability to refer to an enum case generically without reference to any of its associated values.

Let me give you an example:

In our app, we have an enum that represents all the different screens to which the user can navigate. (A screen in our case usually means a view controller or hierarchy thereof.)

Because each screen might require specific view model object(s) to render their content, some of our enum cases have associated values to store the required view model objects.

This allows an enum value to contain all the information needed to present any screen to the user, fully populated with content.

However, in a few instances I've found it would be helpful to be able to refer to a screen in the abstract and be able to 'switch' against it without any associated values. (This would allow me to be able to refer to, say, "the User Account screen" in the abstract, whereas now I can only refer to "the User Account screen displaying details for this particular user".)

I might be missing something, but you can do this already. 'case .CaseWithPayload:' matches any CaseWithPayload regardless of its payload.

-Joe

We've identified two possible solutions to this issue and have implemented one of them, but it is still sub-optimal:

• One option involves maintaining a parallel enum with the same case names but without any associated values. These parallel structures need to be manually maintained, which is something the compiler cannot enforce.

• Another option involves removing the associated values from the enum and passing around objects to contain the necessary view model objects. At various points, we assert that the view model container object is of the expected type for the enum case, but again, that now moves to runtime an error that otherwise would've been caught by the compiler.

---

When an enum case takes one or more associated values, it acts more like a type than a value because it specifies a format for storing information without specifying the exact informations stored. We're able to refer to other types as such in Swift, but not in this case.

I think it would be helpful if any enum with at least one case had a parallel representation containing the same cases but without associated values. It might look like:

enum Foo
{
    case Bar(String)
    case Baz(Int, Int)

    // generated by the compiler; returns the parallel FooType
    // with cases that don't have associated values
    var enumType: FooType
}

// generated by the compiler when an enum
// has at least one associated value
enum FooType
{
    case Bar
    case Baz
}

This would make it possible to be able to refer to cases in the abstract.

Perhaps there's a totally different solution to this class of problem, but that's what I came up with. Would love to hear your thoughts.

E.

On Dec 10, 2015, at 8:24 AM, plx via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

FWIW, as long as we’re asking for some compiler assistance generating useful enumeration-related boilerplate, I’d like to request that something along these lines be possible in some version of Swift:

@synthesize_case_enum
enum Example {

case Foo(X)
case Bar
case Baz(Y)

}

…which would then by default expand to something like this:

enum ExampleCase : Int {

case Foo
case Bar
case Baz

}

extension Example {

var enumerationCase: ExampleCase {
   get {
     switch self {
       case .Foo(_): return .Foo
       case .Bar(_): return .Bar
       case .Baz(_): return .Baz
     }
   }
}

}

_______________________________________________
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

I might be missing something, but you can do this already. 'case .CaseWithPayload:' matches any CaseWithPayload regardless of its payload.

-Joe

Hi Joe,

Thanks for the reply.

You're referring to the ability to test whether an existing enum value is of a given case regardless of the contents of its associated values. In other words, after a value has been created, you can test for whether it is of a specific case while ignoring any associated values.

I'm talking about the ability to create a value that represents the generic concept of an enum case that has associated values, but without actually specifying any associated values.

In Swift right now, you can programmatically represent an enum case that has associated values only by first supplying those associated values.

I think of it like the difference between a class and an instance. A class defines a type and it defines storage. An instance is of a certain type and puts specific values in the storage. An instance or value is a realization of a class or type. If I have an instance or value, I can ask it to tell me its type. I can store that type in a variable. There is also a notation to allow me to specify any such type as a literal.

Just as I can programmatically refer to the type of an value (or the class of an object instance), I'd like to be able to refer to a case in the abstract without also needing to supply associated values. But that's not possible; an enum case that is declared with associated values can't exist in any form unless and until those values are specified.

Perhaps an example will help. Assume the following enum representing the universe of screens that can be displayed in an app:

enum Screens
{
    case Splash
    case Landing
    case UserPreferences(User)
    case StoreView(Store)
    case SaleView(Sale)
    case ProductView(Product)
}

Some of the cases have associated values, some do not. The ones that have associated values represent screens that require certain input in order to display content.

Now say I want to populate a debug menu that lets testers navigate anywhere in the app. I'd like a way to represent each screen in the app, but without any specific content.

I have an enum of Screens right here, but I can't actually use it for that purpose because I can't create values from it without supplying the associated values right then and there. So I can't add a "func allScreens() -> [Screens]" to the enum to allow me to query for this information.

The simplest work-around for this use case seems to be creating a parallel enum like:

enum ScreenTypes
{
    case Splash
    case Landing
    case UserPreferences
    case StoreView
    case SaleView
    case ProductView

    func allScreens() -> [ScreenTypes]
}

With such an enum, I could populate a debug menu.

Several times now when I've used enums that have associated values, I've wished for a parallel enum that had the same cases, but without associated values, so I could do things like that. I usually end of creating one, but then I lose the ability to have the compiler flag a whole class of errors.

Does my explanation make sense?

All the best,
E.

With such an enum, I could populate a debug menu.

If you just want this for debugging, have you looked at the reflection APIs?

¡¡¡

--
Brent Royal-Gordon
Architechies

I don’t think this suggestion would work in practice. It’s the equivalent of trying to construct a struct value with non-optional properties, but without providing any init parameters, it would result in an invalid value. If your proposal were possible I think it would cause trouble with pattern matching enums too. In a switch statement that expects to bind to associated values, what happens when it receives an enum that should have associated values, but they are not present?

¡¡¡

On 11 Dec 2015, at 04:53, Evan Maloney <emaloney@gilt.com> wrote:

You're referring to the ability to test whether an existing enum value is of a given case regardless of the contents of its associated values. In other words, after a value has been created, you can test for whether it is of a specific case while ignoring any associated values.

I'm talking about the ability to create a value that represents the generic concept of an enum case that has associated values, but without actually specifying any associated values.

In Swift right now, you can programmatically represent an enum case that has associated values only by first supplying those associated values.

If you just want this for debugging, have you looked at the reflection APIs?

Sorry, that’s probably not suitable for your specific use case.

Honestly, I really do think you’re confusing two separate issues: testing which screen you’re on, and navigating to a particular screen. You can test which screen you’re on without paying attention to the specific associated values. But if you then want to navigate to a screen, you’re going to need the associated values anyway. Why would you want a version of your enum which didn’t have them?

(By the way, if your answer is “I want to map meta-enum values to the enum value I’m currently using”, then write a Hashable conformance which ignores the associated values. Then looking up .Foo(a) in a Dictionary will give you .Foo(b) if that’s present instead.)

¡¡¡

--
Brent Royal-Gordon
Architechies

You can already do something like this as well. Sure it's a bit verbose,
but for the cases where you need to ignore the associated value you can do
a one-to-one mapping. You can then simply do a switch(enumVar.type()) { ...
}.

enum EnumType {

    enum EnumTypeType {
        case TypeA
        case TypeB
        case TypeC
        case TypeD
    }

    case TypeA(String)
    case TypeB(Bool)
    case TypeC()
    case TypeD(String)

    func type() -> EnumTypeType {
        switch(self) {
        case .TypeA(_):
            return .TypeA
        case .TypeB(_):
            return .TypeB
        case .TypeC():
            return .TypeC
        case TypeD(_):
            return .TypeD
        }
    }
}

*Sandy Chapman*
*Technical Team Lead*

*Lixar I.T. Inc.*T: 902.405.4443
F: 902.405.4435

schapman@lixar.com

<img src='//cdck-file-uploads-global.s3.dualstack.us-west-2.amazonaws.com/swift/original/1X/80d7d6d30d13f9f33aabd00b6617b58d1c6bd57b.jpg' width='141' height='50'>

¡¡¡

On Fri, Dec 11, 2015 at 8:51 AM, Al Skipp via swift-evolution < swift-evolution@swift.org> wrote:

I don’t think this suggestion would work in practice. It’s the equivalent
of trying to construct a struct value with non-optional properties, but
without providing any init parameters, it would result in an invalid value.
If your proposal were possible I think it would cause trouble with pattern
matching enums too. In a switch statement that expects to bind to
associated values, what happens when it receives an enum that should have
associated values, but they are not present?

On 11 Dec 2015, at 04:53, Evan Maloney <emaloney@gilt.com> wrote:

You're referring to the ability to test whether an existing enum value is
of a given case regardless of the contents of its associated values. In
other words, *after* a value has been created, you can test for whether
it is of a specific case while ignoring any associated values.

I'm talking about the ability to create a value that represents the
generic concept of an enum case that has associated values, but without
actually specifying any associated values.

In Swift right now, you can programmatically represent an enum case that
has associated values *only by first supplying those associated values*.

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

--

You can already do something like this as well. Sure it's a bit verbose, but for the cases where you need to ignore the associated value you can do a one-to-one mapping. You can then simply do a switch(enumVar.type()) { ... }.

enum EnumType {
    
    enum EnumTypeType {
        case TypeA
        case TypeB
        case TypeC
        case TypeD
    }
    
    case TypeA(String)
    case TypeB(Bool)
    case TypeC()
    case TypeD(String)
    
    func type() -> EnumTypeType {
        switch(self) {
        case .TypeA(_):
            return .TypeA
        case .TypeB(_):
            return .TypeB
        case .TypeC():
            return .TypeC
        case TypeD(_):
            return .TypeD
        }
    }
}

I initially considered this option too, but it doesn’t address the question:

I'm talking about the ability to create a value that represents the generic concept of an enum case that has associated values, but without actually specifying any associated values.

The request was the ability to create enums without supplying the associated parameters, the above implementation doesn’t allow that (it’s simply not feasible). Also, it’s possible to pattern match an enum without binding it’s associated values, so there’s no need to create an internal ‘shadow’ enum without the parameters.

A very ugly approach would be to make the associated values Optionals, but that’s quite a hacky thing to do for the use case.

I don’t think this suggestion would work in practice. It’s the equivalent of trying to construct a struct value with non-optional properties, but without providing any init parameters, it would result in an invalid value. If your proposal were possible I think it would cause trouble with pattern matching enums too. In a switch statement that expects to bind to associated values, what happens when it receives an enum that should have associated values, but they are not present?

I am definitely not proposing any change in the current behavior of enums, cases, pattern matching, or anything like that.

I'm proposing adding a way of representing something that currently can't be represented in Swift.

You can match an enum case by ignoring the associated values it contains, but that's matching against a value that has *already been created with associated values*.

There's no way to create a value in Swift that represents the general form of an enum case when that case is declared with associated values. You can only create a value in the specific form, i.e. the form of the case that actually contains the associated values. There's no way to represent the general form.

Bear with my inaccurate analogy here, because it might provide a better explanation of what I'm talking about:

In an enum, when a case has no associated values, you can think of values of that case behaving like a type in that there's only one version of it that can exist: the thing itself. There's no range of values that can be represented by such an enum case; there's just one value.

Now, once you introduce associated values, the concept of an enum case suddenly changes: it no longer represents a single thing, it represents a potential range of things. In other words, realized versions of those case values stop acting like types and start acting like instances of a type.

Anywhere else in Swift where something acts like a value, there's an equivalent metavalue type that can also be represented in a Swift variable.

Why would I want to do this?

It seems to me it's quite common in software development that when you model specific instances of things, you also need a way to represent the general form of those specific things.

In my case, I want to model a set of screens with specific content, I might do that with an enum containing associated values. The case represents the screen, and the associated values represent the content.

However, in addition to representing the specific, I also need to model the general. Instead of modeling screens with specific content, I also need to programmatically model just the screens themselves, without any specific content.

My solution was to allow such enums to opt-in to a protocol that would cause the compiler to generate a parallel enum that contains the same cases, minus the associated values.

This parallel enum would be an entirely different type, and it would not affect the current semantics of the original enum (with the associated values) that it "shadows".

I've run into several use cases for this in about a year of Swift coding, and each time I've come up with a manual work-around (just as others have suggested various ways to work around this) but in each case, I lose the compiler's ability to enforce the conditions that I must now assert at runtime.

E.

1 Like

I'm looking for this ability as well, and posted about it here:

I'm not sure why you needed to resurrect a three-year-old thread just to mention that you posted in a different thread.

3 Likes

That was probably unnecessarily snarky on my part, sorry.

In general, we discourage posting in very old threads because it doesn't lead to better discussions in the present day. It's easy for people reading the thread to skip the huge time gap and reply to things that were said years ago by people who may no longer be around and, even if they are, may not notice the new activity in the old thread, and who almost certainly don't remember the context of the conversation. Some people have asked that we automatically close all the old threads; it's probably a good idea, but I don't know if we have an easy ability to do that.

In general, if you notice that an old conversation is relevant to some new point you're making, it's probably better to just link the old thread instead of posting in it.

2 Likes