[Proposal] Enums with static stored properties for each case

UIBezierPath is shared for all instances of the enum case. So stored
properties are stored per case, not per instance (you have associated
values for per instance values).

that isn't really what this syntax suggests is happening

Please explain what makes you think that way.

···

On Tue, May 31, 2016 at 11:52 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

   case spades {

<snip>

       let bezierPath = UIBezierPath()

Does each instance of `.spades` have a *separate* UIBezierPath, or do all instances of `.spades` share one? If it's the former, I have strong doubts you'll actually get this through. If it's the latter, that isn't really what this syntax suggests is happening.

--
Brent Royal-Gordon
Architechies

I think these are different concepts. Classes and structs are abstractions for something (think of them as empty forms while instances are filled forms) while enums identify a closed set of values (filled forms) known ahead of use. Sealed classes are intended to limit extensions to a class not to the instances that can be created.

···

-----Original Message-----
From: "Charlie Monroe" <charlie@charliemonroe.net>
Sent: ‎26/‎05/‎2016 03:13 PM
To: "Vladimir.S" <svabox@gmail.com>
Cc: "Leonardo Pessoa" <me@lmpessoa.com>; "swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static storedpropertiesforeach case

Now thinking about this, what would solve this partially is being discussed in another topic here - sealed clasees.

Each planet would have its own class and the superclass Planet would be abstract sealed. You would then be able to do an effective switch on the instance of the planet, which would act like an enum.

On May 26, 2016, at 8:06 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

Yes, this was mentioned in a similar thread in this email list earlier. There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which *index*(or key) will be of enum type? *And* compiler will check that value for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:

Java enums automatically have a static values() method that return an array
with all values in an enum.
---------------------------------------------------------------------------
From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎26/‎05/‎2016 02:36 PM
To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static stored
propertiesforeach case

On 26.05.2016 19:50, Ross O'Brien wrote:

Perhaps there's an argument to be made for a sort of 'enumDictionary' type
- a dictionary whose keys are all the cases of an enum, and is thus
guaranteed to produce a value.

In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
type
  TMyEnum = (One, Two)
var
  MyVal : array[TMyEnum] of String
const
  MyConsts : array [TMyEnum] of String = ('just one', 'two here')
  // compiler will check that values for each enum were specified here

,so you can do
var e: TMyEnum
e := One;
MyVal[e] := 'hello';
s2 := MyConsts[e];

This is really useful and used a lot. And this is safe in meaning compiler
will notify you if you changed the enum - you'll have to change such
constant array.

I wish we'll have something like this in Swift.

I think the question I have is how you'd access the values, syntactically.
To use the Planet example, if '.earth' is a value of the Planet enum, is
'.earth.mass' an acceptable way to access its mass? Or perhaps
'Planet[.earth].mass'?

Just like .rawValue currently, i.e.
let e = Planet.earth
print(e.mass, e.description)

On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

   Or(if we are sure we'll don't forget to udpate `infoDict` in case of
   new added case in future):

   enum Planet {
       case earth
       case moon

       struct PlanetInfo {
           var mass: Double
           var description: String
       }

       private static let infoDict = [
           Planet.earth :
               PlanetInfo(mass: 1.0, description:"Earth is our home"),
           .moon:
               PlanetInfo(mass: 0.2, description:"Just a moon"),
           ]

       var info : PlanetInfo { return Planet.infoDict[self]! }
   }

   But I agree with you, IMO we need static stored properties for each case.

   On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:

       The problem is that PlanetInfo values are recreated each time while
       they are static. Imagine if PlanetInfo where some type that expensive
       to create performance wise.

       You could solve it by:

       enum Planet {
           struct PlanetInfo {
               var mass: Double
               var description: String
           }

           case earth
           case moon

           private static earthInfo = PlanetInfo(mass: 1.0, description:
       "Earth is our home")
           private static moonInfo = PlanetInfo(mass: 0.2, description:
       "Just a moon")

           var info : PlanetInfo {
               switch self {
                   case earth: return PlanetInfo.earthInfo
                   case moon: return PlanetInfo.moonInfo
               }
           }
       }

       But that again more verbose. The proposed solution is explicit that
       those properties are static for each case.

       On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

           I support the proposal, but couldn't the initial target be
           achieved today
           with such (more verbose,yes) solution? :

           enum Planet {
               struct PlanetInfo {
                   var mass: Double
                   var description: String
               }

               case earth
               case moon

               var info : PlanetInfo {
                   switch self {
                       case earth: return PlanetInfo(mass: 1.0,
           description: "Earth is
           our home")
                       case moon: return PlanetInfo(mass: 0.2,
           description: "Just a
           moon")
                   }
               }
           }

           let e = Planet.earth
           print(e, e.info.description)

           let m = Planet.moon
           print(m, m.info.description)

           On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:

                   What this proposal is asking for is an easier way to
                   have derived values
                   from enum cases. Asking for more flexible RawValues
                   means mass and radius
                   are not derived, they are the source of truth. It goes
                   against the whole
                   point of RawRepresentable. You are not saying ‘Mercury
                   is identified by
                   the case .mercury’, you are saying ‘Mercury is
                   identified by a mass of
                   3.303e+23’. It’s backwards.

               I see what Janis meant in the first email. It's not that
               the planet would
               be identified by the mass or radius. It could very much be

               case Mercury = 1 where (mass: 3, radius: 2),

               - Mercury's rawValue would be 1.

               The issue here is that sometimes you want additional
               information with the
               enum. There are many cases where you extend the enum with a
               variable:

               enum Error {
               case NoError
               case FileNotFound
               ...

               var isFatal: Bool {
               /// swtich over all values of self goes here.
               }

               var isNetworkError: Bool {
               /// swtich over all values of self goes here.
               }

               var isIOError: Bool {
               /// swtich over all values of self goes here.
               }
               }

               What the propsal suggests is to simplify this to the

following:

               enum Error {
               var isFatal: Bool

               case NoError where (isFatal: false, isNetworkError: false,
               isIOError:
               false)
               case FileNotFound where (isFatal: true, isNetworkError:
               false, isIOError:
               true)
               ...

               }

               So that you assign the additional information to the enum
               value itself.

               Charlie

                       On 26 May 2016, at 1:47 PM, David Sweeris via
                       swift-evolution
                       <swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>
                       <mailto:swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>>> wrote:

                           On May 25, 2016, at 10:27 PM, Jacob >>> Bandes-Storch <jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com> >>> <mailto:jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com>>> wrote:

                           On Wed, May 25, 2016 at 8:15 PM, David Sweeris
                           via swift-evolution
                           <swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>
                           <mailto:swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>>> wrote:

                               On May 25, 2016, at 7:37 AM, Leonardo
                           Pessoa via swift-evolution
                               <swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>
                           <mailto:swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>>>
                           wrote:

                                   Hi,

                                   Couldn't this be solved by using
                               tuples? If not because the syntax
                                   is not allowed I think this would be
                               more coherent to do it using
                                   current syntax.

                                   enum Planet : (mass: Float, radius:
                               Float) {
                                       case mercury = (mass: 3.303e+23,
                               radius: 2.4397e6)
                                       case venus = (mass: 4.869e+24,
                               radius: 6.0518e6)
                                       case earth = (mass: 5.976e+24,
                               radius: 6.37814e6)
                                       case mars = (mass: 6.421e+23,
                               radius: 3.3972e6)
                                       case jupiter = (mass: 1.9e+27,
                               radius: 7.1492e7)
                                       case saturn = (mass: 5.688e+26,
                               radius: 6.0268e7)
                                       case uranus = (mass: 8.686e+25,
                               radius: 2.5559e7)
                                       case neptune = (mass: 1.024e+26,
                               radius: 2.4746e7)
                                   }

                               This would be my preferred solution… AFAIK,
                           the only reason we
                               can’t do it now is that Swift currently
                           requires RawValue be an
                               integer, floating-point value, or string. I
                           don’t know why the
                               language has this restriction, so I can’t
                           comment on how hard it
                               would be to change.

                               - Dave Sweeris

                           Except you'd have to write
                           Planet.mercury.rawValue.mass, rather than
                           Planet.mercury.mass.

                           This could be one or two proposals: allow enums
                           with tuple RawValues,
                           and allow `TupleName.caseName.propertyName` to
                           access a tuple element
                           without going through .rawValue.

                       Good point… Has there been a thread on allowing
                       raw-valued enums to be
                       treated as constants of type `RawValue` yet? Either
                       way, removing the
                       restriction on what types can be a RawValue is
                       still my preferred
                       solution.

                       - Dave Sweeris
                       _______________________________________________
                       swift-evolution mailing list
                       swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>
                       <mailto: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>
                   <mailto: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

   _______________________________________________
   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
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 get it and think this was really very interesting in Delphi and I wouldn't mind having something like this in Swift. But despite being able to extend associated information through the use of another array we'd still have more verbosity and scattering than with tuples to implement the examples discussed. And we can already have enum dictionaries just not checking automatically if all enum values have been covered. Moreover there is no loss in having both solutions.

I mentioned the values() method also because I miss a way to iterate through all the values on an enum and since it seems we're discussing the entire way to work with enums here it was worth bringing it up.

···

-----Original Message-----
From: "Vladimir.S" <svabox@gmail.com>
Sent: ‎26/‎05/‎2016 03:06 PM
To: "Leonardo Pessoa" <me@lmpessoa.com>
Cc: "swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static storedpropertiesforeach case

Yes, this was mentioned in a similar thread in this email list earlier.
There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary
with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which
*index*(or key) will be of enum type? *And* compiler will check that value
for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:

Java enums automatically have a static values() method that return an array
with all values in an enum.
---------------------------------------------------------------------------
From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎26/‎05/‎2016 02:36 PM
To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static stored
propertiesforeach case

On 26.05.2016 19:50, Ross O'Brien wrote:

Perhaps there's an argument to be made for a sort of 'enumDictionary' type
- a dictionary whose keys are all the cases of an enum, and is thus
guaranteed to produce a value.

In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
type
   TMyEnum = (One, Two)
var
   MyVal : array[TMyEnum] of String
const
   MyConsts : array [TMyEnum] of String = ('just one', 'two here')
   // compiler will check that values for each enum were specified here

,so you can do
var e: TMyEnum
e := One;
MyVal[e] := 'hello';
s2 := MyConsts[e];

This is really useful and used a lot. And this is safe in meaning compiler
will notify you if you changed the enum - you'll have to change such
constant array.

I wish we'll have something like this in Swift.

I think the question I have is how you'd access the values, syntactically.
To use the Planet example, if '.earth' is a value of the Planet enum, is
'.earth.mass' an acceptable way to access its mass? Or perhaps
'Planet[.earth].mass'?

Just like .rawValue currently, i.e.
let e = Planet.earth
print(e.mass, e.description)

On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    Or(if we are sure we'll don't forget to udpate `infoDict` in case of
    new added case in future):

    enum Planet {
        case earth
        case moon

        struct PlanetInfo {
            var mass: Double
            var description: String
        }

        private static let infoDict = [
            Planet.earth :
                PlanetInfo(mass: 1.0, description:"Earth is our home"),
            .moon:
                PlanetInfo(mass: 0.2, description:"Just a moon"),
            ]

        var info : PlanetInfo { return Planet.infoDict[self]! }
    }

    But I agree with you, IMO we need static stored properties for each case.

    On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:

        The problem is that PlanetInfo values are recreated each time while
        they are static. Imagine if PlanetInfo where some type that expensive
        to create performance wise.

        You could solve it by:

        enum Planet {
            struct PlanetInfo {
                var mass: Double
                var description: String
            }

            case earth
            case moon

            private static earthInfo = PlanetInfo(mass: 1.0, description:
        "Earth is our home")
            private static moonInfo = PlanetInfo(mass: 0.2, description:
        "Just a moon")

            var info : PlanetInfo {
                switch self {
                    case earth: return PlanetInfo.earthInfo
                    case moon: return PlanetInfo.moonInfo
                }
            }
        }

        But that again more verbose. The proposed solution is explicit that
        those properties are static for each case.

        On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

            I support the proposal, but couldn't the initial target be
            achieved today
            with such (more verbose,yes) solution? :

            enum Planet {
                struct PlanetInfo {
                    var mass: Double
                    var description: String
                }

                case earth
                case moon

                var info : PlanetInfo {
                    switch self {
                        case earth: return PlanetInfo(mass: 1.0,
            description: "Earth is
            our home")
                        case moon: return PlanetInfo(mass: 0.2,
            description: "Just a
            moon")
                    }
                }
            }

            let e = Planet.earth
            print(e, e.info.description)

            let m = Planet.moon
            print(m, m.info.description)

            On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:

                    What this proposal is asking for is an easier way to
                    have derived values
                    from enum cases. Asking for more flexible RawValues
                    means mass and radius
                    are not derived, they are the source of truth. It goes
                    against the whole
                    point of RawRepresentable. You are not saying ‘Mercury
                    is identified by
                    the case .mercury’, you are saying ‘Mercury is
                    identified by a mass of
                    3.303e+23’. It’s backwards.

                I see what Janis meant in the first email. It's not that
                the planet would
                be identified by the mass or radius. It could very much be

                case Mercury = 1 where (mass: 3, radius: 2),

                - Mercury's rawValue would be 1.

                The issue here is that sometimes you want additional
                information with the
                enum. There are many cases where you extend the enum with a
                variable:

                enum Error {
                case NoError
                case FileNotFound
                ...

                var isFatal: Bool {
                /// swtich over all values of self goes here.
                }

                var isNetworkError: Bool {
                /// swtich over all values of self goes here.
                }

                var isIOError: Bool {
                /// swtich over all values of self goes here.
                }
                }

                What the propsal suggests is to simplify this to the

following:

                enum Error {
                var isFatal: Bool

                case NoError where (isFatal: false, isNetworkError: false,
                isIOError:
                false)
                case FileNotFound where (isFatal: true, isNetworkError:
                false, isIOError:
                true)
                ...

                }

                So that you assign the additional information to the enum
                value itself.

                Charlie

                        On 26 May 2016, at 1:47 PM, David Sweeris via
                        swift-evolution
                        <swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        <mailto:swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>>> wrote:

                            On May 25, 2016, at 10:27 PM, Jacob >> Bandes-Storch <jtbandes@gmail.com >> <mailto:jtbandes@gmail.com> >> <mailto:jtbandes@gmail.com >> <mailto:jtbandes@gmail.com>>> wrote:

                            On Wed, May 25, 2016 at 8:15 PM, David Sweeris
                            via swift-evolution
                            <swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>
                            <mailto:swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>>> wrote:

                                On May 25, 2016, at 7:37 AM, Leonardo
                            Pessoa via swift-evolution
                                <swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>
                            <mailto:swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>>>
                            wrote:

                                    Hi,

                                    Couldn't this be solved by using
                                tuples? If not because the syntax
                                    is not allowed I think this would be
                                more coherent to do it using
                                    current syntax.

                                    enum Planet : (mass: Float, radius:
                                Float) {
                                        case mercury = (mass: 3.303e+23,
                                radius: 2.4397e6)
                                        case venus = (mass: 4.869e+24,
                                radius: 6.0518e6)
                                        case earth = (mass: 5.976e+24,
                                radius: 6.37814e6)
                                        case mars = (mass: 6.421e+23,
                                radius: 3.3972e6)
                                        case jupiter = (mass: 1.9e+27,
                                radius: 7.1492e7)
                                        case saturn = (mass: 5.688e+26,
                                radius: 6.0268e7)
                                        case uranus = (mass: 8.686e+25,
                                radius: 2.5559e7)
                                        case neptune = (mass: 1.024e+26,
                                radius: 2.4746e7)
                                    }

                                This would be my preferred solution… AFAIK,
                            the only reason we
                                can’t do it now is that Swift currently
                            requires RawValue be an
                                integer, floating-point value, or string. I
                            don’t know why the
                                language has this restriction, so I can’t
                            comment on how hard it
                                would be to change.

                                - Dave Sweeris

                            Except you'd have to write
                            Planet.mercury.rawValue.mass, rather than
                            Planet.mercury.mass.

                            This could be one or two proposals: allow enums
                            with tuple RawValues,
                            and allow `TupleName.caseName.propertyName` to
                            access a tuple element
                            without going through .rawValue.

                        Good point… Has there been a thread on allowing
                        raw-valued enums to be
                        treated as constants of type `RawValue` yet? Either
                        way, removing the
                        restriction on what types can be a RawValue is
                        still my preferred
                        solution.

                        - Dave Sweeris
                        _______________________________________________
                        swift-evolution mailing list
                        swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        <mailto: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>
                    <mailto: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

    _______________________________________________
    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
https://lists.swift.org/mailman/listinfo/swift-evolution

Now thinking about this, what would solve this partially is being discussed in another topic here - sealed clasees.

Each planet would have its own class and the superclass Planet would be abstract sealed. You would then be able to do an effective switch on the instance of the planet, which would act like an enum.

···

On May 26, 2016, at 8:06 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

Yes, this was mentioned in a similar thread in this email list earlier. There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which *index*(or key) will be of enum type? *And* compiler will check that value for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:

Java enums automatically have a static values() method that return an array
with all values in an enum.
---------------------------------------------------------------------------
From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎26/‎05/‎2016 02:36 PM
To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static stored
propertiesforeach case

On 26.05.2016 19:50, Ross O'Brien wrote:

Perhaps there's an argument to be made for a sort of 'enumDictionary' type
- a dictionary whose keys are all the cases of an enum, and is thus
guaranteed to produce a value.

In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
type
  TMyEnum = (One, Two)
var
  MyVal : array[TMyEnum] of String
const
  MyConsts : array [TMyEnum] of String = ('just one', 'two here')
  // compiler will check that values for each enum were specified here

,so you can do
var e: TMyEnum
e := One;
MyVal[e] := 'hello';
s2 := MyConsts[e];

This is really useful and used a lot. And this is safe in meaning compiler
will notify you if you changed the enum - you'll have to change such
constant array.

I wish we'll have something like this in Swift.

I think the question I have is how you'd access the values, syntactically.
To use the Planet example, if '.earth' is a value of the Planet enum, is
'.earth.mass' an acceptable way to access its mass? Or perhaps
'Planet[.earth].mass'?

Just like .rawValue currently, i.e.
let e = Planet.earth
print(e.mass, e.description)

On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

   Or(if we are sure we'll don't forget to udpate `infoDict` in case of
   new added case in future):

   enum Planet {
       case earth
       case moon

       struct PlanetInfo {
           var mass: Double
           var description: String
       }

       private static let infoDict = [
           Planet.earth :
               PlanetInfo(mass: 1.0, description:"Earth is our home"),
           .moon:
               PlanetInfo(mass: 0.2, description:"Just a moon"),
           ]

       var info : PlanetInfo { return Planet.infoDict[self]! }
   }

   But I agree with you, IMO we need static stored properties for each case.

   On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:

       The problem is that PlanetInfo values are recreated each time while
       they are static. Imagine if PlanetInfo where some type that expensive
       to create performance wise.

       You could solve it by:

       enum Planet {
           struct PlanetInfo {
               var mass: Double
               var description: String
           }

           case earth
           case moon

           private static earthInfo = PlanetInfo(mass: 1.0, description:
       "Earth is our home")
           private static moonInfo = PlanetInfo(mass: 0.2, description:
       "Just a moon")

           var info : PlanetInfo {
               switch self {
                   case earth: return PlanetInfo.earthInfo
                   case moon: return PlanetInfo.moonInfo
               }
           }
       }

       But that again more verbose. The proposed solution is explicit that
       those properties are static for each case.

       On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

           I support the proposal, but couldn't the initial target be
           achieved today
           with such (more verbose,yes) solution? :

           enum Planet {
               struct PlanetInfo {
                   var mass: Double
                   var description: String
               }

               case earth
               case moon

               var info : PlanetInfo {
                   switch self {
                       case earth: return PlanetInfo(mass: 1.0,
           description: "Earth is
           our home")
                       case moon: return PlanetInfo(mass: 0.2,
           description: "Just a
           moon")
                   }
               }
           }

           let e = Planet.earth
           print(e, e.info.description)

           let m = Planet.moon
           print(m, m.info.description)

           On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:

                   What this proposal is asking for is an easier way to
                   have derived values
                   from enum cases. Asking for more flexible RawValues
                   means mass and radius
                   are not derived, they are the source of truth. It goes
                   against the whole
                   point of RawRepresentable. You are not saying ‘Mercury
                   is identified by
                   the case .mercury’, you are saying ‘Mercury is
                   identified by a mass of
                   3.303e+23’. It’s backwards.

               I see what Janis meant in the first email. It's not that
               the planet would
               be identified by the mass or radius. It could very much be

               case Mercury = 1 where (mass: 3, radius: 2),

               - Mercury's rawValue would be 1.

               The issue here is that sometimes you want additional
               information with the
               enum. There are many cases where you extend the enum with a
               variable:

               enum Error {
               case NoError
               case FileNotFound
               ...

               var isFatal: Bool {
               /// swtich over all values of self goes here.
               }

               var isNetworkError: Bool {
               /// swtich over all values of self goes here.
               }

               var isIOError: Bool {
               /// swtich over all values of self goes here.
               }
               }

               What the propsal suggests is to simplify this to the

following:

               enum Error {
               var isFatal: Bool

               case NoError where (isFatal: false, isNetworkError: false,
               isIOError:
               false)
               case FileNotFound where (isFatal: true, isNetworkError:
               false, isIOError:
               true)
               ...

               }

               So that you assign the additional information to the enum
               value itself.

               Charlie

                       On 26 May 2016, at 1:47 PM, David Sweeris via
                       swift-evolution
                       <swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>
                       <mailto:swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>>> wrote:

                           On May 25, 2016, at 10:27 PM, Jacob >>> Bandes-Storch <jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com> >>> <mailto:jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com>>> wrote:

                           On Wed, May 25, 2016 at 8:15 PM, David Sweeris
                           via swift-evolution
                           <swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>
                           <mailto:swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>>> wrote:

                               On May 25, 2016, at 7:37 AM, Leonardo
                           Pessoa via swift-evolution
                               <swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>
                           <mailto:swift-evolution@swift.org
                           <mailto:swift-evolution@swift.org>>>
                           wrote:

                                   Hi,

                                   Couldn't this be solved by using
                               tuples? If not because the syntax
                                   is not allowed I think this would be
                               more coherent to do it using
                                   current syntax.

                                   enum Planet : (mass: Float, radius:
                               Float) {
                                       case mercury = (mass: 3.303e+23,
                               radius: 2.4397e6)
                                       case venus = (mass: 4.869e+24,
                               radius: 6.0518e6)
                                       case earth = (mass: 5.976e+24,
                               radius: 6.37814e6)
                                       case mars = (mass: 6.421e+23,
                               radius: 3.3972e6)
                                       case jupiter = (mass: 1.9e+27,
                               radius: 7.1492e7)
                                       case saturn = (mass: 5.688e+26,
                               radius: 6.0268e7)
                                       case uranus = (mass: 8.686e+25,
                               radius: 2.5559e7)
                                       case neptune = (mass: 1.024e+26,
                               radius: 2.4746e7)
                                   }

                               This would be my preferred solution… AFAIK,
                           the only reason we
                               can’t do it now is that Swift currently
                           requires RawValue be an
                               integer, floating-point value, or string. I
                           don’t know why the
                               language has this restriction, so I can’t
                           comment on how hard it
                               would be to change.

                               - Dave Sweeris

                           Except you'd have to write
                           Planet.mercury.rawValue.mass, rather than
                           Planet.mercury.mass.

                           This could be one or two proposals: allow enums
                           with tuple RawValues,
                           and allow `TupleName.caseName.propertyName` to
                           access a tuple element
                           without going through .rawValue.

                       Good point… Has there been a thread on allowing
                       raw-valued enums to be
                       treated as constants of type `RawValue` yet? Either
                       way, removing the
                       restriction on what types can be a RawValue is
                       still my preferred
                       solution.

                       - Dave Sweeris
                       _______________________________________________
                       swift-evolution mailing list
                       swift-evolution@swift.org
                       <mailto:swift-evolution@swift.org>
                       <mailto: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>
                   <mailto: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

   _______________________________________________
   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
https://lists.swift.org/mailman/listinfo/swift-evolution

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

Not really. When you take Scala's case classes, they are exactly for this purpose:

http://docs.scala-lang.org/tutorials/tour/case-classes.html

abstract class Term
case class Var(name: String) extends Term
case class Fun(arg: String, body: Term) extends Term
case class App(f: Term, v: Term) extends Term

Which in Swift could be an enum.

You can look at sealed classes in two ways:

1) Something that prevents others from subclassing your classes.
2) Something that ensures that only a known number of subclasses exists at compile-time - which is pretty much the definition of an enum.

···

On May 26, 2016, at 9:48 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

I think these are different concepts. Classes and structs are abstractions for something (think of them as empty forms while instances are filled forms) while enums identify a closed set of values (filled forms) known ahead of use. Sealed classes are intended to limit extensions to a class not to the instances that can be created.

From: Charlie Monroe <mailto:charlie@charliemonroe.net>
Sent: ‎26/‎05/‎2016 03:13 PM
To: Vladimir.S <mailto:svabox@gmail.com>
Cc: Leonardo Pessoa <mailto:me@lmpessoa.com>; swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static storedpropertiesforeach case

Now thinking about this, what would solve this partially is being discussed in another topic here - sealed clasees.

Each planet would have its own class and the superclass Planet would be abstract sealed. You would then be able to do an effective switch on the instance of the planet, which would act like an enum.

> On May 26, 2016, at 8:06 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:
>
> Yes, this was mentioned in a similar thread in this email list earlier. There is even some proposal for such .values() for Swift enums.
>
> But this values() in Java is not the same thing as discussed dictionary with *keys* of enum type or Delphi's arrays with *index* of enum type.
>
> Could you write Java's example for array/dictionary of String which *index*(or key) will be of enum type? *And* compiler will check that value for each enum case is set in case of array of constants like:
> MyConsts : array [TMyEnum] of String = ('just one', 'two here')
> // compiler will always check that value assigned for each case
>
>
> On 26.05.2016 20:58, Leonardo Pessoa wrote:
>> Java enums automatically have a static values() method that return an array
>> with all values in an enum.
>> ---------------------------------------------------------------------------
>> From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
>> Sent: ‎26/‎05/‎2016 02:36 PM
>> To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
>> Cc: swift-evolution <mailto:swift-evolution@swift.org>
>> Subject: Re: [swift-evolution] [Proposal] Enums with static stored
>> propertiesforeach case
>>
>> On 26.05.2016 19:50, Ross O'Brien wrote:
>>> Perhaps there's an argument to be made for a sort of 'enumDictionary' type
>>> - a dictionary whose keys are all the cases of an enum, and is thus
>>> guaranteed to produce a value.
>>
>> In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
>> type
>> TMyEnum = (One, Two)
>> var
>> MyVal : array[TMyEnum] of String
>> const
>> MyConsts : array [TMyEnum] of String = ('just one', 'two here')
>> // compiler will check that values for each enum were specified here
>>
>> ,so you can do
>> var e: TMyEnum
>> e := One;
>> MyVal[e] := 'hello';
>> s2 := MyConsts[e];
>>
>> This is really useful and used a lot. And this is safe in meaning compiler
>> will notify you if you changed the enum - you'll have to change such
>> constant array.
>>
>> I wish we'll have something like this in Swift.
>>
>>>
>>> I think the question I have is how you'd access the values, syntactically.
>>> To use the Planet example, if '.earth' is a value of the Planet enum, is
>>> '.earth.mass' an acceptable way to access its mass? Or perhaps
>>> 'Planet[.earth].mass'?
>>
>> Just like .rawValue currently, i.e.
>> let e = Planet.earth
>> print(e.mass, e.description)
>>
>>>
>>> On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution > >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> Or(if we are sure we'll don't forget to udpate `infoDict` in case of
>>> new added case in future):
>>>
>>> enum Planet {
>>> case earth
>>> case moon
>>>
>>> struct PlanetInfo {
>>> var mass: Double
>>> var description: String
>>> }
>>>
>>> private static let infoDict = [
>>> Planet.earth :
>>> PlanetInfo(mass: 1.0, description:"Earth is our home"),
>>> .moon:
>>> PlanetInfo(mass: 0.2, description:"Just a moon"),
>>> ]
>>>
>>> var info : PlanetInfo { return Planet.infoDict[self]! }
>>> }
>>>
>>> But I agree with you, IMO we need static stored properties for each case.
>>>
>>>
>>> On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:
>>>
>>> The problem is that PlanetInfo values are recreated each time while
>>> they are static. Imagine if PlanetInfo where some type that expensive
>>> to create performance wise.
>>>
>>> You could solve it by:
>>>
>>> enum Planet {
>>> struct PlanetInfo {
>>> var mass: Double
>>> var description: String
>>> }
>>>
>>> case earth
>>> case moon
>>>
>>> private static earthInfo = PlanetInfo(mass: 1.0, description:
>>> "Earth is our home")
>>> private static moonInfo = PlanetInfo(mass: 0.2, description:
>>> "Just a moon")
>>>
>>> var info : PlanetInfo {
>>> switch self {
>>> case earth: return PlanetInfo.earthInfo
>>> case moon: return PlanetInfo.moonInfo
>>> }
>>> }
>>> }
>>>
>>> But that again more verbose. The proposed solution is explicit that
>>> those properties are static for each case.
>>>
>>>
>>> On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution > >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>>
>>> I support the proposal, but couldn't the initial target be
>>> achieved today
>>> with such (more verbose,yes) solution? :
>>>
>>> enum Planet {
>>> struct PlanetInfo {
>>> var mass: Double
>>> var description: String
>>> }
>>>
>>> case earth
>>> case moon
>>>
>>> var info : PlanetInfo {
>>> switch self {
>>> case earth: return PlanetInfo(mass: 1.0,
>>> description: "Earth is
>>> our home")
>>> case moon: return PlanetInfo(mass: 0.2,
>>> description: "Just a
>>> moon")
>>> }
>>> }
>>> }
>>>
>>>
>>> let e = Planet.earth
>>> print(e, e.info.description)
>>>
>>> let m = Planet.moon
>>> print(m, m.info.description)
>>>
>>>
>>>
>>> On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:
>>>
>>>
>>> What this proposal is asking for is an easier way to
>>> have derived values
>>> from enum cases. Asking for more flexible RawValues
>>> means mass and radius
>>> are not derived, they are the source of truth. It goes
>>> against the whole
>>> point of RawRepresentable. You are not saying ‘Mercury
>>> is identified by
>>> the case .mercury’, you are saying ‘Mercury is
>>> identified by a mass of
>>> 3.303e+23’. It’s backwards.
>>>
>>>
>>>
>>> I see what Janis meant in the first email. It's not that
>>> the planet would
>>> be identified by the mass or radius. It could very much be
>>>
>>> case Mercury = 1 where (mass: 3, radius: 2),
>>>
>>> - Mercury's rawValue would be 1.
>>>
>>> The issue here is that sometimes you want additional
>>> information with the
>>> enum. There are many cases where you extend the enum with a
>>> variable:
>>>
>>> enum Error {
>>> case NoError
>>> case FileNotFound
>>> ...
>>>
>>> var isFatal: Bool {
>>> /// swtich over all values of self goes here.
>>> }
>>>
>>> var isNetworkError: Bool {
>>> /// swtich over all values of self goes here.
>>> }
>>>
>>> var isIOError: Bool {
>>> /// swtich over all values of self goes here.
>>> }
>>> }
>>>
>>> What the propsal suggests is to simplify this to the
>> following:
>>>
>>> enum Error {
>>> var isFatal: Bool
>>>
>>> case NoError where (isFatal: false, isNetworkError: false,
>>> isIOError:
>>> false)
>>> case FileNotFound where (isFatal: true, isNetworkError:
>>> false, isIOError:
>>> true)
>>> ...
>>>
>>> }
>>>
>>> So that you assign the additional information to the enum
>>> value itself.
>>>
>>> Charlie
>>>
>>>
>>>
>>> On 26 May 2016, at 1:47 PM, David Sweeris via
>>> swift-evolution
>>> <swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>
>>> <mailto:swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>>
>>> On May 25, 2016, at 10:27 PM, Jacob > >>> Bandes-Storch <jtbandes@gmail.com > >>> <mailto:jtbandes@gmail.com> > >>> <mailto:jtbandes@gmail.com > >>> <mailto:jtbandes@gmail.com>>> wrote:
>>>
>>> On Wed, May 25, 2016 at 8:15 PM, David Sweeris
>>> via swift-evolution
>>> <swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>
>>> <mailto:swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>>> wrote:
>>>
>>> On May 25, 2016, at 7:37 AM, Leonardo
>>> Pessoa via swift-evolution
>>> <swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>
>>> <mailto:swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>>>
>>> wrote:
>>>
>>>
>>>
>>> Hi,
>>>
>>> Couldn't this be solved by using
>>> tuples? If not because the syntax
>>> is not allowed I think this would be
>>> more coherent to do it using
>>> current syntax.
>>>
>>> enum Planet : (mass: Float, radius:
>>> Float) {
>>> case mercury = (mass: 3.303e+23,
>>> radius: 2.4397e6)
>>> case venus = (mass: 4.869e+24,
>>> radius: 6.0518e6)
>>> case earth = (mass: 5.976e+24,
>>> radius: 6.37814e6)
>>> case mars = (mass: 6.421e+23,
>>> radius: 3.3972e6)
>>> case jupiter = (mass: 1.9e+27,
>>> radius: 7.1492e7)
>>> case saturn = (mass: 5.688e+26,
>>> radius: 6.0268e7)
>>> case uranus = (mass: 8.686e+25,
>>> radius: 2.5559e7)
>>> case neptune = (mass: 1.024e+26,
>>> radius: 2.4746e7)
>>> }
>>>
>>>
>>>
>>> This would be my preferred solution… AFAIK,
>>> the only reason we
>>> can’t do it now is that Swift currently
>>> requires RawValue be an
>>> integer, floating-point value, or string. I
>>> don’t know why the
>>> language has this restriction, so I can’t
>>> comment on how hard it
>>> would be to change.
>>>
>>> - Dave Sweeris
>>>
>>>
>>> Except you'd have to write
>>> Planet.mercury.rawValue.mass, rather than
>>> Planet.mercury.mass.
>>>
>>> This could be one or two proposals: allow enums
>>> with tuple RawValues,
>>> and allow `TupleName.caseName.propertyName` to
>>> access a tuple element
>>> without going through .rawValue.
>>>
>>>
>>>
>>> Good point… Has there been a thread on allowing
>>> raw-valued enums to be
>>> treated as constants of type `RawValue` yet? Either
>>> way, removing the
>>> restriction on what types can be a RawValue is
>>> still my preferred
>>> solution.
>>>
>>> - Dave Sweeris
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution@swift.org
>>> <mailto:swift-evolution@swift.org>
>>> <mailto: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>
>>> <mailto: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
>>>
>>>
>>> _______________________________________________
>>> 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
>> 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 personally don't like the Java values() solution. Nor the solution based on dictionary where you need to use ! to unwrap the optionals.

There are IMHO only two ways to solve this:

1) allow enums with RawValue being object (AnyClass) and make allow case values to be computed. In the Planet case:

enum Planets: Planet {
  case Earth = Planet(mass: 1, radius: 2)
  ...
}

The switch would be performed using ===, i.e. it would be allowed to have two cases with the same mass and radius.

This unfortunately faces a lot of issues, including if you have an ObjC class that may returns in all cases a singleton and all cases would have the same value. This could be handled by an assertion at launch.

2) allow auto-generation of computed variables on enums (partially as I've proposed):

enum Planets {
  @auto var mass: Double /// @auto indicates it's auto-generated
  @auto var radius: Double

  /// The enum value is .Earth and has mass and radius properties.
  /// All cases would need to declare these and only literals would
  /// be allowed - i.e. numbers + strings.
  case Earth where (mass: 1.0, radius: 2.0)
  ...

}

which would do nothing else than create the following code:

enum Planets {
  var mass: Double {
    switch self {
    case .Earth: return 1.0
    ...
    }
  }

  var radius: Double {
    switch self {
    case .Earth: return 2.0
    ...
    }
  }

  case Earth
}

···

On May 26, 2016, at 10:03 PM, Leonardo Pessoa via swift-evolution <swift-evolution@swift.org> wrote:

I get it and think this was really very interesting in Delphi and I wouldn't mind having something like this in Swift. But despite being able to extend associated information through the use of another array we'd still have more verbosity and scattering than with tuples to implement the examples discussed. And we can already have enum dictionaries just not checking automatically if all enum values have been covered. Moreover there is no loss in having both solutions.

I mentioned the values() method also because I miss a way to iterate through all the values on an enum and since it seems we're discussing the entire way to work with enums here it was worth bringing it up.

From: Vladimir.S <mailto:svabox@gmail.com>
Sent: ‎26/‎05/‎2016 03:06 PM
To: Leonardo Pessoa <mailto:me@lmpessoa.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static storedpropertiesforeach case

Yes, this was mentioned in a similar thread in this email list earlier.
There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary
with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which
*index*(or key) will be of enum type? *And* compiler will check that value
for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:
> Java enums automatically have a static values() method that return an array
> with all values in an enum.
> ---------------------------------------------------------------------------
> From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
> Sent: ‎26/‎05/‎2016 02:36 PM
> To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
> Cc: swift-evolution <mailto:swift-evolution@swift.org>
> Subject: Re: [swift-evolution] [Proposal] Enums with static stored
> propertiesforeach case
>
> On 26.05.2016 19:50, Ross O'Brien wrote:
>> Perhaps there's an argument to be made for a sort of 'enumDictionary' type
>> - a dictionary whose keys are all the cases of an enum, and is thus
>> guaranteed to produce a value.
>
> In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
> type
> TMyEnum = (One, Two)
> var
> MyVal : array[TMyEnum] of String
> const
> MyConsts : array [TMyEnum] of String = ('just one', 'two here')
> // compiler will check that values for each enum were specified here
>
> ,so you can do
> var e: TMyEnum
> e := One;
> MyVal[e] := 'hello';
> s2 := MyConsts[e];
>
> This is really useful and used a lot. And this is safe in meaning compiler
> will notify you if you changed the enum - you'll have to change such
> constant array.
>
> I wish we'll have something like this in Swift.
>
>>
>> I think the question I have is how you'd access the values, syntactically.
>> To use the Planet example, if '.earth' is a value of the Planet enum, is
>> '.earth.mass' an acceptable way to access its mass? Or perhaps
>> 'Planet[.earth].mass'?
>
> Just like .rawValue currently, i.e.
> let e = Planet.earth
> print(e.mass, e.description)
>
>>
>> On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution > >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> Or(if we are sure we'll don't forget to udpate `infoDict` in case of
>> new added case in future):
>>
>> enum Planet {
>> case earth
>> case moon
>>
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> private static let infoDict = [
>> Planet.earth :
>> PlanetInfo(mass: 1.0, description:"Earth is our home"),
>> .moon:
>> PlanetInfo(mass: 0.2, description:"Just a moon"),
>> ]
>>
>> var info : PlanetInfo { return Planet.infoDict[self]! }
>> }
>>
>> But I agree with you, IMO we need static stored properties for each case.
>>
>>
>> On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:
>>
>> The problem is that PlanetInfo values are recreated each time while
>> they are static. Imagine if PlanetInfo where some type that expensive
>> to create performance wise.
>>
>> You could solve it by:
>>
>> enum Planet {
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> case earth
>> case moon
>>
>> private static earthInfo = PlanetInfo(mass: 1.0, description:
>> "Earth is our home")
>> private static moonInfo = PlanetInfo(mass: 0.2, description:
>> "Just a moon")
>>
>> var info : PlanetInfo {
>> switch self {
>> case earth: return PlanetInfo.earthInfo
>> case moon: return PlanetInfo.moonInfo
>> }
>> }
>> }
>>
>> But that again more verbose. The proposed solution is explicit that
>> those properties are static for each case.
>>
>>
>> On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution > >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>>
>> I support the proposal, but couldn't the initial target be
>> achieved today
>> with such (more verbose,yes) solution? :
>>
>> enum Planet {
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> case earth
>> case moon
>>
>> var info : PlanetInfo {
>> switch self {
>> case earth: return PlanetInfo(mass: 1.0,
>> description: "Earth is
>> our home")
>> case moon: return PlanetInfo(mass: 0.2,
>> description: "Just a
>> moon")
>> }
>> }
>> }
>>
>>
>> let e = Planet.earth
>> print(e, e.info.description)
>>
>> let m = Planet.moon
>> print(m, m.info.description)
>>
>>
>>
>> On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:
>>
>>
>> What this proposal is asking for is an easier way to
>> have derived values
>> from enum cases. Asking for more flexible RawValues
>> means mass and radius
>> are not derived, they are the source of truth. It goes
>> against the whole
>> point of RawRepresentable. You are not saying ‘Mercury
>> is identified by
>> the case .mercury’, you are saying ‘Mercury is
>> identified by a mass of
>> 3.303e+23’. It’s backwards.
>>
>>
>>
>> I see what Janis meant in the first email. It's not that
>> the planet would
>> be identified by the mass or radius. It could very much be
>>
>> case Mercury = 1 where (mass: 3, radius: 2),
>>
>> - Mercury's rawValue would be 1.
>>
>> The issue here is that sometimes you want additional
>> information with the
>> enum. There are many cases where you extend the enum with a
>> variable:
>>
>> enum Error {
>> case NoError
>> case FileNotFound
>> ...
>>
>> var isFatal: Bool {
>> /// swtich over all values of self goes here.
>> }
>>
>> var isNetworkError: Bool {
>> /// swtich over all values of self goes here.
>> }
>>
>> var isIOError: Bool {
>> /// swtich over all values of self goes here.
>> }
>> }
>>
>> What the propsal suggests is to simplify this to the
> following:
>>
>> enum Error {
>> var isFatal: Bool
>>
>> case NoError where (isFatal: false, isNetworkError: false,
>> isIOError:
>> false)
>> case FileNotFound where (isFatal: true, isNetworkError:
>> false, isIOError:
>> true)
>> ...
>>
>> }
>>
>> So that you assign the additional information to the enum
>> value itself.
>>
>> Charlie
>>
>>
>>
>> On 26 May 2016, at 1:47 PM, David Sweeris via
>> swift-evolution
>> <swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>> wrote:
>>
>>
>> On May 25, 2016, at 10:27 PM, Jacob > >> Bandes-Storch <jtbandes@gmail.com > >> <mailto:jtbandes@gmail.com> > >> <mailto:jtbandes@gmail.com > >> <mailto:jtbandes@gmail.com>>> wrote:
>>
>> On Wed, May 25, 2016 at 8:15 PM, David Sweeris
>> via swift-evolution
>> <swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>> wrote:
>>
>> On May 25, 2016, at 7:37 AM, Leonardo
>> Pessoa via swift-evolution
>> <swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>>
>> wrote:
>>
>>
>>
>> Hi,
>>
>> Couldn't this be solved by using
>> tuples? If not because the syntax
>> is not allowed I think this would be
>> more coherent to do it using
>> current syntax.
>>
>> enum Planet : (mass: Float, radius:
>> Float) {
>> case mercury = (mass: 3.303e+23,
>> radius: 2.4397e6)
>> case venus = (mass: 4.869e+24,
>> radius: 6.0518e6)
>> case earth = (mass: 5.976e+24,
>> radius: 6.37814e6)
>> case mars = (mass: 6.421e+23,
>> radius: 3.3972e6)
>> case jupiter = (mass: 1.9e+27,
>> radius: 7.1492e7)
>> case saturn = (mass: 5.688e+26,
>> radius: 6.0268e7)
>> case uranus = (mass: 8.686e+25,
>> radius: 2.5559e7)
>> case neptune = (mass: 1.024e+26,
>> radius: 2.4746e7)
>> }
>>
>>
>>
>> This would be my preferred solution… AFAIK,
>> the only reason we
>> can’t do it now is that Swift currently
>> requires RawValue be an
>> integer, floating-point value, or string. I
>> don’t know why the
>> language has this restriction, so I can’t
>> comment on how hard it
>> would be to change.
>>
>> - Dave Sweeris
>>
>>
>> Except you'd have to write
>> Planet.mercury.rawValue.mass, rather than
>> Planet.mercury.mass.
>>
>> This could be one or two proposals: allow enums
>> with tuple RawValues,
>> and allow `TupleName.caseName.propertyName` to
>> access a tuple element
>> without going through .rawValue.
>>
>>
>>
>> Good point… Has there been a thread on allowing
>> raw-valued enums to be
>> treated as constants of type `RawValue` yet? Either
>> way, removing the
>> restriction on what types can be a RawValue is
>> still my preferred
>> solution.
>>
>> - Dave Sweeris
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>
>> <mailto: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>
>> <mailto: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
>>
>>
>> _______________________________________________
>> 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
> 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 get it and think this was really very interesting in Delphi and I
wouldn't mind having something like this in Swift. But despite being able
to extend associated information through the use of another array we'd
still have more verbosity and scattering than with tuples to implement the
examples discussed.

At this moment I think your proposal for tuples as raw value for enum is the best. So we can ask just to support tuples(not other types, at least yet) as raw type and use tuple values directly on enum instance(without `.rawValue.`). The question is if this is doable and if there is a support for this in community and in core team. (even for post Swift 3.0 era)
As I understand, for this we need implicit implementation of Equatable for tuple as raw value and probably of RawRepresentable.

>And we can already have enum dictionaries just not

checking automatically if all enum values have been covered. Moreover there
is no loss in having both solutions.

As for dictionary. I don't think of it as implementation detail for static stored properties for each case. Such dictionary could be helpful in other situations when you need assign some value for each enum case in your code. *The main point* is a feature that compiler checks that value is assigned for *each* case.

For example, in your code you need to assign color for each case in Planets. You can do this in switch:

switch e {
   case .earth : color = colorA
   case .moon : color = colorB
}

but instead you can create a dict:
let planetToColor = [Planet.earth : colorA, .moon : colorB]
and use as planetToColor[e]! // yes, have to use `!` here

But, this is *not safe*(but very handy and useful) - as if you *add* new case in enum (let's say .mars) you will not be notified(in opposite to switch) that your planetToColor must me changed also - it does not contain color for .mars. You will know about this only in runtime.

So, it will be very good for our code, if we have such dictionary which will check at compile time that all cases are presented as keys in it.

I mentioned the values() method also because I miss a way to iterate
through all the values on an enum and since it seems we're discussing the
entire way to work with enums here it was worth bringing it up.

There was "ValueEnumerable protocol with derived implementation for enums" thread in this mailing list, you can review discussion in it regarding "values()" feature.
I also wish someone create a proposal to improve enums in a number of ways.

···

On 26.05.2016 23:03, Leonardo Pessoa wrote:

---------------------------------------------------------------------------
From: Vladimir.S <mailto:svabox@gmail.com>
Sent: ‎26/‎05/‎2016 03:06 PM
To: Leonardo Pessoa <mailto:me@lmpessoa.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static
storedpropertiesforeach case

Yes, this was mentioned in a similar thread in this email list earlier.
There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary
with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which
*index*(or key) will be of enum type? *And* compiler will check that value
for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:

Java enums automatically have a static values() method that return an array
with all values in an enum.
---------------------------------------------------------------------------
From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎26/‎05/‎2016 02:36 PM
To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static stored
propertiesforeach case

On 26.05.2016 19:50, Ross O'Brien wrote:

Perhaps there's an argument to be made for a sort of 'enumDictionary' type
- a dictionary whose keys are all the cases of an enum, and is thus
guaranteed to produce a value.

In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
type
   TMyEnum = (One, Two)
var
   MyVal : array[TMyEnum] of String
const
   MyConsts : array [TMyEnum] of String = ('just one', 'two here')
   // compiler will check that values for each enum were specified here

,so you can do
var e: TMyEnum
e := One;
MyVal[e] := 'hello';
s2 := MyConsts[e];

This is really useful and used a lot. And this is safe in meaning compiler
will notify you if you changed the enum - you'll have to change such
constant array.

I wish we'll have something like this in Swift.

I think the question I have is how you'd access the values, syntactically.
To use the Planet example, if '.earth' is a value of the Planet enum, is
'.earth.mass' an acceptable way to access its mass? Or perhaps
'Planet[.earth].mass'?

Just like .rawValue currently, i.e.
let e = Planet.earth
print(e.mass, e.description)

On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

    Or(if we are sure we'll don't forget to udpate `infoDict` in case of
    new added case in future):

    enum Planet {
        case earth
        case moon

        struct PlanetInfo {
            var mass: Double
            var description: String
        }

        private static let infoDict = [
            Planet.earth :
                PlanetInfo(mass: 1.0, description:"Earth is our home"),
            .moon:
                PlanetInfo(mass: 0.2, description:"Just a moon"),
            ]

        var info : PlanetInfo { return Planet.infoDict[self]! }
    }

    But I agree with you, IMO we need static stored properties for each

case.

    On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:

        The problem is that PlanetInfo values are recreated each time while
        they are static. Imagine if PlanetInfo where some type that

expensive

        to create performance wise.

        You could solve it by:

        enum Planet {
            struct PlanetInfo {
                var mass: Double
                var description: String
            }

            case earth
            case moon

            private static earthInfo = PlanetInfo(mass: 1.0, description:
        "Earth is our home")
            private static moonInfo = PlanetInfo(mass: 0.2, description:
        "Just a moon")

            var info : PlanetInfo {
                switch self {
                    case earth: return PlanetInfo.earthInfo
                    case moon: return PlanetInfo.moonInfo
                }
            }
        }

        But that again more verbose. The proposed solution is explicit that
        those properties are static for each case.

        On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> > wrote:

            I support the proposal, but couldn't the initial target be
            achieved today
            with such (more verbose,yes) solution? :

            enum Planet {
                struct PlanetInfo {
                    var mass: Double
                    var description: String
                }

                case earth
                case moon

                var info : PlanetInfo {
                    switch self {
                        case earth: return PlanetInfo(mass: 1.0,
            description: "Earth is
            our home")
                        case moon: return PlanetInfo(mass: 0.2,
            description: "Just a
            moon")
                    }
                }
            }

            let e = Planet.earth
            print(e, e.info.description)

            let m = Planet.moon
            print(m, m.info.description)

            On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:

                    What this proposal is asking for is an easier way to
                    have derived values
                    from enum cases. Asking for more flexible RawValues
                    means mass and radius
                    are not derived, they are the source of truth. It goes
                    against the whole
                    point of RawRepresentable. You are not saying ‘Mercury
                    is identified by
                    the case .mercury’, you are saying ‘Mercury is
                    identified by a mass of
                    3.303e+23’. It’s backwards.

                I see what Janis meant in the first email. It's not that
                the planet would
                be identified by the mass or radius. It could very much be

                case Mercury = 1 where (mass: 3, radius: 2),

                - Mercury's rawValue would be 1.

                The issue here is that sometimes you want additional
                information with the
                enum. There are many cases where you extend the enum with a
                variable:

                enum Error {
                case NoError
                case FileNotFound
                ...

                var isFatal: Bool {
                /// swtich over all values of self goes here.
                }

                var isNetworkError: Bool {
                /// swtich over all values of self goes here.
                }

                var isIOError: Bool {
                /// swtich over all values of self goes here.
                }

                What the propsal suggests is to simplify this to the

following:

                enum Error {
                var isFatal: Bool

                case NoError where (isFatal: false, isNetworkError: false,
                isIOError:
                false)
                case FileNotFound where (isFatal: true, isNetworkError:
                false, isIOError:
                true)
                ...

                }

                So that you assign the additional information to the enum
                value itself.

                Charlie

                        On 26 May 2016, at 1:47 PM, David Sweeris via
                        swift-evolution
                        <swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        <mailto:swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>>> wrote:

                            On May 25, 2016, at 10:27 PM, Jacob >>> Bandes-Storch <jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com> >>> <mailto:jtbandes@gmail.com >>> <mailto:jtbandes@gmail.com>>> wrote:

                            On Wed, May 25, 2016 at 8:15 PM, David Sweeris
                            via swift-evolution
                            <swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>
                            <mailto:swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>>> wrote:

                                On May 25, 2016, at 7:37 AM, Leonardo
                            Pessoa via swift-evolution
                                <swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>
                            <mailto:swift-evolution@swift.org
                            <mailto:swift-evolution@swift.org>>>
                            wrote:

                                    Hi,

                                    Couldn't this be solved by using
                                tuples? If not because the syntax
                                    is not allowed I think this would be
                                more coherent to do it using
                                    current syntax.

                                    enum Planet : (mass: Float, radius:
                                Float) {
                                        case mercury = (mass: 3.303e+23,
                                radius: 2.4397e6)
                                        case venus = (mass: 4.869e+24,
                                radius: 6.0518e6)
                                        case earth = (mass: 5.976e+24,
                                radius: 6.37814e6)
                                        case mars = (mass: 6.421e+23,
                                radius: 3.3972e6)
                                        case jupiter = (mass: 1.9e+27,
                                radius: 7.1492e7)
                                        case saturn = (mass: 5.688e+26,
                                radius: 6.0268e7)
                                        case uranus = (mass: 8.686e+25,
                                radius: 2.5559e7)
                                        case neptune = (mass: 1.024e+26,
                                radius: 2.4746e7)
                                    }

                                This would be my preferred solution… AFAIK,
                            the only reason we
                                can’t do it now is that Swift currently
                            requires RawValue be an
                                integer, floating-point value, or string. I
                            don’t know why the
                                language has this restriction, so I can’t
                            comment on how hard it
                                would be to change.

                                - Dave Sweeris

                            Except you'd have to write
                            Planet.mercury.rawValue.mass, rather than
                            Planet.mercury.mass.

                            This could be one or two proposals: allow enums
                            with tuple RawValues,
                            and allow `TupleName.caseName.propertyName` to
                            access a tuple element
                            without going through .rawValue.

                        Good point… Has there been a thread on allowing
                        raw-valued enums to be
                        treated as constants of type `RawValue` yet? Either
                        way, removing the
                        restriction on what types can be a RawValue is
                        still my preferred
                        solution.

                        - Dave Sweeris
                        _______________________________________________
                        swift-evolution mailing list
                        swift-evolution@swift.org
                        <mailto:swift-evolution@swift.org>
                        <mailto: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>
                    <mailto: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

    _______________________________________________
    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
https://lists.swift.org/mailman/listinfo/swift-evolution

One thing I did often in Java (and miss in Swift) is using their enums to build state machines or implement command patterns for common commands.

Java enums are a sealed set of subclasses of the enum base type with (hopefully) immutable, singleton instances. So you can do fun things like:
- Define the base class constructor to be called to instantiate the subclasses, and declare the cases with the constructor arguments
- Declare a method on the base type and refine it on 1-2 particular cases
- Declare the enum implements an interface, and implement that interface separately for each case.
- Define data accessors specific to the type (such as the planets example above)

I like the SuitInfo approach below - with extensions, I think I can get close to what I have done in the past with Java. Maybe one day there is syntax to do this in the language directly

-DW

···

On May 31, 2016, at 11:44 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

I'm not sure about my opinion on this proposal, but I believe you should add this as alternatives of how we can have the similar features today without injecting stored properties into enums :

enum Suit {
   case spades
   case hearts
   case diamonds
   case clubs

   struct SuitInfo {
       let simpleDescription: String
       let color: UIColor
       let symbol: String
       let bezierPath: UIBezierPath
   }

   var info : SuitInfo {
       switch self {
       case .spades:
           let path = UIBezierPath()
           // omitted lines ...

           return SuitInfo(
               simpleDescription: "spades",
               color: .blackColor(),
               symbol: ":spades:",
               bezierPath: path)

       case .hearts:
           let path = UIBezierPath()
           // omitted lines ...

           return SuitInfo(
               simpleDescription: "hearts",
               color: .redColor(),
               symbol: ":heart:",
               bezierPath: path)

       case .diamonds:
           let path = UIBezierPath()
           // omitted lines ...

           return SuitInfo(
               simpleDescription: "diamonds",
               color: .redColor(),
               symbol: ":diamonds:",
               bezierPath: path)

       case .clubs:
           let path = UIBezierPath()
           // omitted lines ...

           return SuitInfo(
               simpleDescription: "clubs",
               color: .blackColor(),
               symbol: ":clubs:",
               bezierPath: path)

       }
   }
}

and this:

enum Suit {
   case spades
   case hearts
   case diamonds
   case clubs

   struct SuitInfo {
       let simpleDescription: String
       let color: UIColor
       let symbol: String
       let bezierPath: UIBezierPath
   }

   static let spadesInfo : SuitInfo = {
       let path = UIBezierPath()
       // omitted lines ...

       return SuitInfo(
           simpleDescription: "spades",
           color: .blackColor(),
           symbol: ":spades:",
           bezierPath: path)
   }()

   static let heartsInfo : SuitInfo = {
       let path = UIBezierPath()
       // omitted lines ...

       return SuitInfo(
           simpleDescription: "hearts",
           color: .redColor(),
           symbol: ":heart:",
           bezierPath: path)
   }()

   static let diamondsInfo : SuitInfo = {
       let path = UIBezierPath()
       // omitted lines ...

       return SuitInfo(
           simpleDescription: "diamonds",
           color: .redColor(),
           symbol: ":diamonds:",
           bezierPath: path)
   }()

   static let clubsInfo : SuitInfo = {
       let path = UIBezierPath()
       // omitted lines ...

       return SuitInfo(
           simpleDescription: "clubs",
           color: .blackColor(),
           symbol: ":clubs:",
           bezierPath: path)
   }()

   var info : SuitInfo {
       switch self {
           case .spades: return Suit.spadesInfo
           case .hearts: return Suit.heartsInfo
           case .diamonds: return Suit.diamondsInfo
           case .clubs: return Suit.clubsInfo
       }
   }
}

On 31.05.2016 17:17, Jānis Kiršteins via swift-evolution wrote:

I wrote a proposal draft:

# Enum case stored properties

* Proposal: TBD
* Author: [Janis Kirsteins](https://github.com/kirsteins\)
* Status: TBD
* Review manager: TBD

## Introduction

This proposal allows each enum case to have stored properties.

## Motivation

Enums cases can have a lot of constant (or variable) static values
associated with it. For example, planets can have mass, radius, age,
closest star etc. Currently there is no way to set or get those values
easily.

Example below shows that is hard to read and manage static associated
values with each case. It is hard to add or remove case as it would
require to add or remove code in four different places in file. Also
static associated value like `UIBezierPath` is recreated each time the
property is computed while it's constant.

enum Suit {
   case spades
   case hearts
   case diamonds
   case clubs

   var simpleDescription: String {
       switch self {
       case .spades:
           return "spades"
       case .hearts:
           return "hearts"
       case .diamonds:
           return "diamonds"
       case .clubs:
           return "clubs"
       }
   }

   var color: UIColor {
       switch self {
       case .spades:
           return .blackColor()
       case .hearts:
           return .redColor()
       case .diamonds:
           return .redColor()
       case .clubs:
           return .blackColor()
       }
   }

   var symbol: String {
       switch self {
       case .spades:
           return "♠"
       case .hearts:
           return "♥"
       case .diamonds:
           return "♦"
       case .clubs:
           return "♣"
       }
   }

   var bezierPath: UIBezierPath {
       switch self {
       case .spades:
           let path = UIBezierPath()
           // omitted lines ...
           return path
       case .hearts:
           let path = UIBezierPath()
           // omitted lines ...
           return path
       case .diamonds:
           let path = UIBezierPath()
           // omitted lines ...
           return path
       case .clubs:
           let path = UIBezierPath()
           // omitted lines ...
           return path
       }
   }
}

## Proposed solution

Support stored properties for enum cases just as each case were an
instance. Case properties are initialized block after each case
declaration.

enum Suit {
   let simpleDescription: String
   let color: UIColor
   let symbol: String
   let bezierPath: UIBezierPath

   case spades {
       simpleDescription = "spades"
       color = .blackColor()
       symbol = "♠"
       let bezierPath = UIBezierPath()
       // omitted lines ...
       self.bezierPath = bezierPath
   }

   case hearts {
       simpleDescription = "hearts"
       color = .redColor()
       symbol = "♥"
       let bezierPath = UIBezierPath()
       // omitted lines ...
       self.bezierPath = bezierPath
   }

   case diamonds {
       simpleDescription = "diamonds"
       color = .redColor()
       symbol = "♦"
       let bezierPath = UIBezierPath()
       // omitted lines ...
       self.bezierPath = bezierPath
   }

   case clubs {
       simpleDescription = "clubs"
       color = .blackColor()
       symbol = "♣"
       let bezierPath = UIBezierPath()
       // omitted lines ...
       self.bezierPath = bezierPath
   }
}

let symbol = Suit.spades.symbol // "♠"

The proposed solution improves:
- Readability as cases are closer with their related data;
- Improves code maintainability as a case can be removed or added in one place;
- Improved performance as there is no need to recreate static values;
- ~30% less lines of code in given example.

## Detailed design

#### Stored properties

Enum stored properties are supported the same way they are supported
for structs can classes. Unlike enum associated values, stored
properties are static to case and are shared for the same case.

Properties are accessed:

let simpleDescription = Suit.spades.simpleDescription

Mutable properties can be set:

Suit.spades.simpleDescription = "new simple description"

#### Initialization

If enum has uninitialized stored property it must be initialized in a
block after each case declaration. The block work the same way as
struct initialization. At the end of initialization block all
properties must be initialized.

enum Suit {
   var simpleDescription: String

   case spades {
       simpleDescription = "spades"
   }
}

Initialization block can be combine with use of `rawValue`:

enum Suit: Int {
   var simpleDescription: String

   case spades = 1 {
       simpleDescription = "spades"
   }
}

or associated values of the case:

enum Suit {
   var simpleDescription: String

   case spades(Int) {
       simpleDescription = "spades"
   }
}

## Impact on existing code

Stored properties for enums are not currently not supported, so there
is no impact on existing code.

## Alternatives considered

- Use labeled tuple as `rawValue` of the enum case. This approach is
not compatible as it conflicts with intention of `rawValue` of Swift
enum;
- Use per case initializer like [Java
Enum](JDK 21 Documentation - Home).
Swift enum uses custom initializer syntax to setup instances, not
cases. So this approach is not suitable for Swift.

On Sun, May 29, 2016 at 3:42 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

I think that's the case with enums. You're changing their current behaviour of only having stored values to one in which it's computed (even if only once and then stored). Enums are IMO something that have a static value you know beforehand and can count on. That's why I'm not fond of the accessor proposal. Otherwise I think we're transforming enums into a closed set of struct instances and one could do that already by using a private init.

On 29 May 2016, at 3:38 am, Jānis Kiršteins via swift-evolution <swift-evolution@swift.org> wrote:

I agree with the argument about use of "where", not replacing the raw
value and having some kind of initialization block. But I cannot see
why "accessors" concept is any better than stored properties to solve
the particular problem. The "accessors" concept has much wider scope
than enums and is a separate proposal.

On Sat, May 28, 2016 at 11:39 PM, Brent Royal-Gordon >>>> <brent@architechies.com> wrote:

- Abusing rawValue is just that: an abuse.

My original proposal does not replace rawValue and is compatible with it.

`rawValue` has a different purpose from how you're using it. It's supposed to allow you to convert your type to some other *equivalent* type, like an equivalent integer or string. Moreover, it's supposed to allow you to *reconstruct* the instance from the raw value—remember, `RawRepresentable` has an `init(rawValue:)` requirement.

It is *not* supposed to be an ancillary bag of information on the side. You're cramming a square peg into a round hole here.

(Also, if you use `rawValue` for an ancillary bag of information, that means you *can't* use it on the same type for its intended purpose. For instance, you would not be able to assign numbers to your Planet enum's cases to help you serialize them or bridge them to Objective-C. That's not good.)

- Using `where` just doesn't match the use of `where` elsewhere in the language; everywhere else, it's some kind of condition.

It is also used in generic type constraints. Plus it reads like human
language: `case mercury where (mass: 3.303e+23, radius: 2.4397e6)`

But a generic constraint is also a type of condition: it specifies types which are permitted and divides them from types that are not.

This is *not* a condition. It's not anything like a condition. It's simply not consistent with anything else in the language.

- Dictionaries are the most straightforward way to handle this with the current language, but their lack of exhaustiveness checking is a problem.

Dictionaries can be used as workaround, but they cannot (lack of
exhaustiveness) solve the problem.

I agree that they're a halfway solution.

If `ValuesEnumerable` were to be accepted (and to have a generic requirement for its `allValues` property), you could write a Dictionary-like type which ensured at initialization time that it was exhaustive. That's not as good as compile time, but it's not bad—sort of a three-quarters solution.

      struct ExhaustiveDictionary<Key: Hashable, Value where Key: ValuesEnumerable>: Collection, DictionaryLiteralConvertible {
              private var dictionary: [Key: Value]

              init(dictionaryLiteral elements: (Key, Value)...) {
                      dictionary = [:]
                      for (k, v) in elements {
                              dictionary[k] = v
                      }

                      if dictionary.count != Key.allValues.count {
                              let missingKeys = Key.allValues.filter { dictionary[$0] == nil }
                              preconditionFailure("ExhaustiveDictionary is missing elements from \(Key.self): \(missingKeys)")
                      }
              }

              var startIndex: Dictionary.Index {
                      return dictionary.startIndex
              }
              var endIndex: Dictionary.Index {
                      return dictionary.endIndex
              }
              subscript(index: Dictionary.Index) -> (Key, Value) {
                      return dictionary[index]
              }
              func index(after i: Dictionary.Index) -> Dictionary.Index {
                      return dictionary.index(after: i)
              }

              subscript(key: Key) -> Value {
                      get { return dictionary[key]! }
                      set { dictionary[key] = newValue }
              }
      }

What I would do is borrow the "accessors" concept from the property behaviors proposal and extend it so that it supported both functions and variables.

Wouldn't accessor just be a redundant keyword here? Currently enums do
not support stored properties, so I guess there is no extra need to
mark properties with any special keyword.

The keyword is mainly to indicate the unusual syntax at the definition site, where you only have to specify the name of the accessor you're defining, not a `func` or `var` keyword, a return type, or even parameter names. (Like `willSet`, there's a default parameter name you can use.) Secondarily, though, I think it's helpful to indicate very explicitly that this is not an ordinary method or property definition, even if the compiler could perhaps sort things out without it. `accessor` is something a user can Google if they've never seen it before.

Property accessors might work for enums with associated values, but
not so well without them.

The two have nothing to do with each other. I showed your planets example, which has no associated values but uses accessors just fine.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

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

UIBezierPath is shared for all instances of the enum case. So stored
properties are stored per case, not per instance (you have associated
values for per instance values).

that isn't really what this syntax suggests is happening

Please explain what makes you think that way.

Because you wrote `let bezierPath = UIBezierPath()` in the middle of a type definition, and in all other types, you would get a new bezier path for each instance.

  struct Struct {
    let bezierPath = UIBezierPath() // per instance
  }
  class Class {
    let bezierPath = UIBezierPath() // per instance
  }
  func function() {
    let bezierPath = UIBezierPath() // per call
  }
  enum Enum {
    case aCase {
      let bezierPath = UIBezierPath() // shared?!?!
    }
  }

···

--
Brent Royal-Gordon
Architechies

Ok, I'm not familiar with Scala but if the language does not have support for the type of enums we're discussing it may be their chosen mechanism to handle enums with associated values (feel free to correct me if I'm wrong always) but my main point for enums is still: do we really need to introduce another concept to handle the presented examples or can we reuse an existing concept? Enums are (or can be seen as) our case classes but there seems to exist a need for enums to hold more than just one value as of today.

Just to mention ahead, I'm not in favour of enum values having methods or computed properties

···

-----Original Message-----
From: "Charlie Monroe" <charlie@charliemonroe.net>
Sent: ‎26/‎05/‎2016 04:57 PM
To: "Leonardo Pessoa" <me@lmpessoa.com>
Cc: "Vladimir.S" <svabox@gmail.com>; "swift-evolution" <swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with staticstoredpropertiesforeach case

Not really. When you take Scala's case classes, they are exactly for this purpose:

http://docs.scala-lang.org/tutorials/tour/case-classes.html

abstract class Term

case class Var(name: String) extends Term

case class Fun(arg: String, body: Term) extends Term

case class App(f: Term, v: Term) extends Term

Which in Swift could be an enum.

You can look at sealed classes in two ways:

1) Something that prevents others from subclassing your classes.
2) Something that ensures that only a known number of subclasses exists at compile-time - which is pretty much the definition of an enum.

On May 26, 2016, at 9:48 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:

I think these are different concepts. Classes and structs are abstractions for something (think of them as empty forms while instances are filled forms) while enums identify a closed set of values (filled forms) known ahead of use. Sealed classes are intended to limit extensions to a class not to the instances that can be created.

From: Charlie Monroe
Sent: ‎26/‎05/‎2016 03:13 PM
To: Vladimir.S
Cc: Leonardo Pessoa; swift-evolution
Subject: Re: [swift-evolution] [Proposal] Enums with static storedpropertiesforeach case

Now thinking about this, what would solve this partially is being discussed in another topic here - sealed clasees.

Each planet would have its own class and the superclass Planet would be abstract sealed. You would then be able to do an effective switch on the instance of the planet, which would act like an enum.

On May 26, 2016, at 8:06 PM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

Yes, this was mentioned in a similar thread in this email list earlier. There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which *index*(or key) will be of enum type? *And* compiler will check that value for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:

Java enums automatically have a static values() method that return an array
with all values in an enum.
---------------------------------------------------------------------------
From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
Sent: ‎26/‎05/‎2016 02:36 PM
To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static stored
propertiesforeach case

On 26.05.2016 19:50, Ross O'Brien wrote:

Perhaps there's an argument to be made for a sort of 'enumDictionary' type
- a dictionary whose keys are all the cases of an enum, and is thus
guaranteed to produce a value.

In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
type
  TMyEnum = (One, Two)
var
  MyVal : array[TMyEnum] of String
const
  MyConsts : array [TMyEnum] of String = ('just one', 'two here')
  // compiler will check that values for each enum were specified here

,so you can do
var e: TMyEnum
e := One;
MyVal[e] := 'hello';
s2 := MyConsts[e];

This is really useful and used a lot. And this is safe in meaning compiler
will notify you if you changed the enum - you'll have to change such
constant array.

I wish we'll have something like this in Swift.

I think the question I have is how you'd access the values, syntactically.
To use the Planet example, if '.earth' is a value of the Planet enum, is
'.earth.mass' an acceptable way to access its mass? Or perhaps
'Planet[.earth].mass'?

Just like .rawValue currently, i.e.
let e = Planet.earth
print(e.mass, e.description)

On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

   Or(if we are sure we'll don't forget to udpate `infoDict` in case of
   new added case in future):

   enum Planet {
       case earth
       case moon

       struct PlanetInfo {
           var mass: Double
           var description: String
       }

       private static let infoDict = [
           Planet.earth :
               PlanetInfo(mass: 1.0, description:"Earth is our home"),
           .moon:
               PlanetInfo(mass: 0.2, description:"Just a moon"),
           ]

       var info : PlanetInfo { return Planet.infoDict[self]! }
   }

   But I agree with you, IMO we need static stored properties for each case.

   On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:

       The problem is that PlanetInfo values are recreated each time while
       they are static. Imagine if PlanetInfo where some type that expensive
       to create performance wise.

       You could solve it by:

       enum Planet {
           struct PlanetInfo {
               var mass: Double
               var description: String
           }

           case earth
           case moon

           private static earthInfo = PlanetInfo(mass: 1.0, description:
       "Earth is our home")
           private static moonInfo = PlanetInfo(mass: 0.2, description:
       "Just a moon")

           var info : PlanetInfo {
               switch self {
                   case earth: return PlanetInfo.earthInfo
                   case moon: return PlanetInfo.moonInfo
               }
           }
       }

       But that again more verbose. The proposed solution is explicit that
       those properties are static for each case.

       On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

           I support the proposal, but couldn't the initial target be
           achieved today
           with such (more verbose,yes) solution? :

           enum Planet {
               struct PlanetInfo {
                   var mass: Double
                   var description: String
               }

               case earth
               case moon

               var info : PlanetInfo {
                   switch self {
                       case earth: return PlanetInfo(mass: 1.0,
           description: "Earth is
           our home")
                       case moon: return PlanetInfo(mass: 0.2,
           description: "Just a
           moon")
                   }
               }
           }

           let e = Planet.earth
           print(e, e.info.description)

           let m = Planet.moon
           print(m, m.info.description)

           On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:

                   What this proposal is asking for is an easier way to
                   have derived values
                   from enum cases. Asking for more flexible RawValues
                   means mass and radius
                   are not derived, they are the source of truth. It goes
                   against the whole
                   point of RawRepresentable. You are not saying ‘Mercury
                   is identified by<br

[The entire original message is not included.]

IMO (now I agree with Leonardo) all we need is allowing a tuple as raw type for enum and in this case compiler should allow as to skip '.rawValue.' and to use tuple values on enum instance directly like:

enum Planets: (mass: Double, description: String) {
   case earth = (mass: 1.0, description: "Earth")
   case moon = (mass: 0.2, description: "Moon")
}

print(Planets.earth.mass)

But for this, enum should allows raw type representation not just by Int/Double/String as now(correct me if forgot something), but at least by tuple.
Currently we can actually have enum Planet : PlanetInfo, but raw value could be represented only with string like

enum Planet : PlanetInfo {
     case earth = "earth" // represents PlanetInfo(1.0, "Earth")
     case moon = "moon" // represents PlanetInfo(0.2, "Moon")
}
and then use:
print(Planets.earth.rawValue.mass)

But you need a lot(relative) of code to make simple PlanetInfo struct RawRepresentable+StringLiteralConvertible+Equatable

Do we actually have some proposal for enum improvement? I mean at least '.allValues' feature and this 'tuple raw value' feature?
Probably additionally I'd like to see some '.next/.prev' methods for enums without associated values.

···

On 26.05.2016 23:27, Charlie Monroe wrote:

I personally don't like the Java values() solution. Nor the solution based
on dictionary where you need to use ! to unwrap the optionals.

There are IMHO only two ways to solve this:

1) allow enums with RawValue being object (AnyClass) and make allow case
values to be computed. In the Planet case:

enum Planets: Planet {
case Earth = Planet(mass: 1, radius: 2)
...
}

The switch would be performed using ===, i.e. it would be allowed to have
two cases with the same mass and radius.

This unfortunately faces a lot of issues, including if you have an ObjC
class that may returns in all cases a singleton and all cases would have
the same value. This could be handled by an assertion at launch.

2) allow auto-generation of computed variables on enums (partially as I've
proposed):

enum Planets {
@auto var mass: Double /// @auto indicates it's auto-generated
@auto var radius: Double

/// The enum value is .Earth and has mass and radius properties.
/// All cases would need to declare these and only literals would
/// be allowed - i.e. numbers + strings.
case Earth where (mass: 1.0, radius: 2.0)
...

}

which would do nothing else than create the following code:

enum Planets {
var mass: Double {
switch self {
case .Earth: return 1.0
...
}

var radius: Double {
switch self {
case .Earth: return 2.0
...
}

case Earth
}

On May 26, 2016, at 10:03 PM, Leonardo Pessoa via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I get it and think this was really very interesting in Delphi and I
wouldn't mind having something like this in Swift. But despite being able
to extend associated information through the use of another array we'd
still have more verbosity and scattering than with tuples to implement
the examples discussed. And we can already have enum dictionaries just
not checking automatically if all enum values have been covered. Moreover
there is no loss in having both solutions.

I mentioned the values() method also because I miss a way to iterate
through all the values on an enum and since it seems we're discussing the
entire way to work with enums here it was worth bringing it up.

---------------------------------------------------------------------------
From: Vladimir.S <mailto:svabox@gmail.com>
Sent: ‎26/‎05/‎2016 03:06 PM
To: Leonardo Pessoa <mailto:me@lmpessoa.com>
Cc: swift-evolution <mailto:swift-evolution@swift.org>
Subject: Re: [swift-evolution] [Proposal] Enums with static
storedpropertiesforeach case

Yes, this was mentioned in a similar thread in this email list earlier.
There is even some proposal for such .values() for Swift enums.

But this values() in Java is not the same thing as discussed dictionary
with *keys* of enum type or Delphi's arrays with *index* of enum type.

Could you write Java's example for array/dictionary of String which
*index*(or key) will be of enum type? *And* compiler will check that value
for each enum case is set in case of array of constants like:
MyConsts : array [TMyEnum] of String = ('just one', 'two here')
// compiler will always check that value assigned for each case

On 26.05.2016 20:58, Leonardo Pessoa wrote:
> Java enums automatically have a static values() method that return an array
> with all values in an enum.
> ---------------------------------------------------------------------------
> From: Vladimir.S via swift-evolution <mailto:swift-evolution@swift.org>
> Sent: ‎26/‎05/‎2016 02:36 PM
> To: Ross O'Brien <mailto:narrativium+swift@gmail.com>
> Cc: swift-evolution <mailto:swift-evolution@swift.org>
> Subject: Re: [swift-evolution] [Proposal] Enums with static stored
> propertiesforeach case
>
> On 26.05.2016 19:50, Ross O'Brien wrote:
>> Perhaps there's an argument to be made for a sort of 'enumDictionary' type
>> - a dictionary whose keys are all the cases of an enum, and is thus
>> guaranteed to produce a value.
>
> In Delphi(Pascal) you can define an array with indexes of enum type i.e.:
> type
> TMyEnum = (One, Two)
> var
> MyVal : array[TMyEnum] of String
> const
> MyConsts : array [TMyEnum] of String = ('just one', 'two here')
> // compiler will check that values for each enum were specified here
>
> ,so you can do
> var e: TMyEnum
> e := One;
> MyVal[e] := 'hello';
> s2 := MyConsts[e];
>
> This is really useful and used a lot. And this is safe in meaning compiler
> will notify you if you changed the enum - you'll have to change such
> constant array.
>
> I wish we'll have something like this in Swift.
>
>>
>> I think the question I have is how you'd access the values, syntactically.
>> To use the Planet example, if '.earth' is a value of the Planet enum, is
>> '.earth.mass' an acceptable way to access its mass? Or perhaps
>> 'Planet[.earth].mass'?
>
> Just like .rawValue currently, i.e.
> let e = Planet.earth
> print(e.mass, e.description)
>
>>
>> On Thu, May 26, 2016 at 4:43 PM, Vladimir.S via swift-evolution >> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> <mailto:swift-evolution@swift.org>> wrote:
>>
>> Or(if we are sure we'll don't forget to udpate `infoDict` in case of
>> new added case in future):
>>
>> enum Planet {
>> case earth
>> case moon
>>
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> private static let infoDict = [
>> Planet.earth :
>> PlanetInfo(mass: 1.0, description:"Earth is our home"),
>> .moon:
>> PlanetInfo(mass: 0.2, description:"Just a moon"),
>> ]
>>
>> var info : PlanetInfo { return Planet.infoDict[self]! }
>> }
>>
>> But I agree with you, IMO we need static stored properties for
each case.
>>
>> On 26.05.2016 18 <tel:26.05.2016%2018>:15, Jānis Kiršteins wrote:
>>
>> The problem is that PlanetInfo values are recreated each time
while
>> they are static. Imagine if PlanetInfo where some type that
expensive
>> to create performance wise.
>>
>> You could solve it by:
>>
>> enum Planet {
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> case earth
>> case moon
>>
>> private static earthInfo = PlanetInfo(mass: 1.0, description:
>> "Earth is our home")
>> private static moonInfo = PlanetInfo(mass: 0.2, description:
>> "Just a moon")
>>
>> var info : PlanetInfo {
>> switch self {
>> case earth: return PlanetInfo.earthInfo
>> case moon: return PlanetInfo.moonInfo
>> }
>> }
>> }
>>
>> But that again more verbose. The proposed solution is explicit
that
>> those properties are static for each case.
>>
>> On Thu, May 26, 2016 at 5:58 PM, Vladimir.S via swift-evolution >> >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> <mailto:swift-evolution@swift.org>> wrote:
>>
>> I support the proposal, but couldn't the initial target be
>> achieved today
>> with such (more verbose,yes) solution? :
>>
>> enum Planet {
>> struct PlanetInfo {
>> var mass: Double
>> var description: String
>> }
>>
>> case earth
>> case moon
>>
>> var info : PlanetInfo {
>> switch self {
>> case earth: return PlanetInfo(mass: 1.0,
>> description: "Earth is
>> our home")
>> case moon: return PlanetInfo(mass: 0.2,
>> description: "Just a
>> moon")
>> }
>> }
>> }
>>
>> let e = Planet.earth
>> print(e, e.info.description)
>>
>> let m = Planet.moon
>> print(m, m.info.description)
>>
>> On 26.05.2016 8:26, Charlie Monroe via swift-evolution wrote:
>>
>> What this proposal is asking for is an easier way to
>> have derived values
>> from enum cases. Asking for more flexible RawValues
>> means mass and radius
>> are not derived, they are the source of truth. It goes
>> against the whole
>> point of RawRepresentable. You are not saying ‘Mercury
>> is identified by
>> the case .mercury’, you are saying ‘Mercury is
>> identified by a mass of
>> 3.303e+23’. It’s backwards.
>>
>> I see what Janis meant in the first email. It's not that
>> the planet would
>> be identified by the mass or radius. It could very much be
>>
>> case Mercury = 1 where (mass: 3, radius: 2),
>>
>> - Mercury's rawValue would be 1.
>>
>> The issue here is that sometimes you want additional
>> information with the
>> enum. There are many cases where you extend the enum
with a
>> variable:
>>
>> enum Error {
>> case NoError
>> case FileNotFound
>> ...
>>
>> var isFatal: Bool {
>> /// swtich over all values of self goes here.
>> }
>>
>> var isNetworkError: Bool {
>> /// swtich over all values of self goes here.
>> }
>>
>> var isIOError: Bool {
>> /// swtich over all values of self goes here.
>> }
>>
>> What the propsal suggests is to simplify this to the
> following:
>>
>> enum Error {
>> var isFatal: Bool
>>
>> case NoError where (isFatal: false, isNetworkError: false,
>> isIOError:
>> false)
>> case FileNotFound where (isFatal: true, isNetworkError:
>> false, isIOError:
>> true)
>> ...
>>
>> }
>>
>> So that you assign the additional information to the enum
>> value itself.
>>
>> Charlie
>>
>> On 26 May 2016, at 1:47 PM, David Sweeris via
>> swift-evolution
>> <swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>> wrote:
>>
>> On May 25, 2016, at 10:27 PM, Jacob
>> Bandes-Storch <jtbandes@gmail.com
<mailto:jtbandes@gmail.com>
>> <mailto:jtbandes@gmail.com>
>> <mailto:jtbandes@gmail.com
>> <mailto:jtbandes@gmail.com>>> wrote:
>>
>> On Wed, May 25, 2016 at 8:15 PM, David Sweeris
>> via swift-evolution
>> <swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>> wrote:
>>
>> On May 25, 2016, at 7:37 AM, Leonardo
>> Pessoa via swift-evolution
>> <swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org
>> <mailto:swift-evolution@swift.org>>>
>> wrote:
>>
>> Hi,
>>
>> Couldn't this be solved by using
>> tuples? If not because the syntax
>> is not allowed I think this would be
>> more coherent to do it using
>> current syntax.
>>
>> enum Planet : (mass: Float, radius:
>> Float) {
>> case mercury = (mass: 3.303e+23,
>> radius: 2.4397e6)
>> case venus = (mass: 4.869e+24,
>> radius: 6.0518e6)
>> case earth = (mass: 5.976e+24,
>> radius: 6.37814e6)
>> case mars = (mass: 6.421e+23,
>> radius: 3.3972e6)
>> case jupiter = (mass: 1.9e+27,
>> radius: 7.1492e7)
>> case saturn = (mass: 5.688e+26,
>> radius: 6.0268e7)
>> case uranus = (mass: 8.686e+25,
>> radius: 2.5559e7)
>> case neptune = (mass: 1.024e+26,
>> radius: 2.4746e7)
>> }
>>
>> This would be my preferred solution…
AFAIK,
>> the only reason we
>> can’t do it now is that Swift currently
>> requires RawValue be an
>> integer, floating-point value, or
string. I
>> don’t know why the
>> language has this restriction, so I can’t
>> comment on how hard it
>> would be to change.
>>
>> - Dave Sweeris
>>
>> Except you'd have to write
>> Planet.mercury.rawValue.mass, rather than
>> Planet.mercury.mass.
>>
>> This could be one or two proposals: allow
enums
>> with tuple RawValues,
>> and allow `TupleName.caseName.propertyName` to
>> access a tuple element
>> without going through .rawValue.
>>
>> Good point… Has there been a thread on allowing
>> raw-valued enums to be
>> treated as constants of type `RawValue` yet?
Either
>> way, removing the
>> restriction on what types can be a RawValue is
>> still my preferred
>> solution.
>>
>> - Dave Sweeris
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution@swift.org
<mailto:swift-evolution@swift.org>
>> <mailto:swift-evolution@swift.org>
>> <mailto: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>
>> <mailto:swift-evolution@swift.org>
>> <mailto: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> <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> <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>
<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

One thing I did often in Java (and miss in Swift) is using their enums to build state machines or implement command patterns for common commands.

Java enums are a sealed set of subclasses of the enum base type with (hopefully) immutable, singleton instances. So you can do fun things like:
- Define the base class constructor to be called to instantiate the subclasses, and declare the cases with the constructor arguments
- Declare a method on the base type and refine it on 1-2 particular cases
- Declare the enum implements an interface, and implement that interface separately for each case.
- Define data accessors specific to the type (such as the planets example above)

I like the SuitInfo approach below - with extensions, I think I can get close to what I have done in the past with Java. Maybe one day there is syntax to do this in the language directly

This is pretty similar to what we were discussing last week in this thread: [swift-evolution] [Pitch] Exhaustive pattern matching for protocols and classes

I'm planning to write up a proposal when I have time (hopefully in the next week or so).

···

Sent from my iPad

On Jun 1, 2016, at 9:48 AM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

-DW

On May 31, 2016, at 11:44 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

I'm not sure about my opinion on this proposal, but I believe you should add this as alternatives of how we can have the similar features today without injecting stored properties into enums :

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  struct SuitInfo {
      let simpleDescription: String
      let color: UIColor
      let symbol: String
      let bezierPath: UIBezierPath
  }

  var info : SuitInfo {
      switch self {
      case .spades:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "spades",
              color: .blackColor(),
              symbol: ":spades:",
              bezierPath: path)

      case .hearts:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "hearts",
              color: .redColor(),
              symbol: ":heart:",
              bezierPath: path)

      case .diamonds:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "diamonds",
              color: .redColor(),
              symbol: ":diamonds:",
              bezierPath: path)

      case .clubs:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "clubs",
              color: .blackColor(),
              symbol: ":clubs:",
              bezierPath: path)

      }
  }
}

and this:

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  struct SuitInfo {
      let simpleDescription: String
      let color: UIColor
      let symbol: String
      let bezierPath: UIBezierPath
  }

  static let spadesInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "spades",
          color: .blackColor(),
          symbol: ":spades:",
          bezierPath: path)
  }()

  static let heartsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "hearts",
          color: .redColor(),
          symbol: ":heart:",
          bezierPath: path)
  }()

  static let diamondsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "diamonds",
          color: .redColor(),
          symbol: ":diamonds:",
          bezierPath: path)
  }()

  static let clubsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "clubs",
          color: .blackColor(),
          symbol: ":clubs:",
          bezierPath: path)
  }()

  var info : SuitInfo {
      switch self {
          case .spades: return Suit.spadesInfo
          case .hearts: return Suit.heartsInfo
          case .diamonds: return Suit.diamondsInfo
          case .clubs: return Suit.clubsInfo
      }
  }
}

On 31.05.2016 17:17, Jānis Kiršteins via swift-evolution wrote:
I wrote a proposal draft:

# Enum case stored properties

* Proposal: TBD
* Author: [Janis Kirsteins](https://github.com/kirsteins\)
* Status: TBD
* Review manager: TBD

## Introduction

This proposal allows each enum case to have stored properties.

## Motivation

Enums cases can have a lot of constant (or variable) static values
associated with it. For example, planets can have mass, radius, age,
closest star etc. Currently there is no way to set or get those values
easily.

Example below shows that is hard to read and manage static associated
values with each case. It is hard to add or remove case as it would
require to add or remove code in four different places in file. Also
static associated value like `UIBezierPath` is recreated each time the
property is computed while it's constant.

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  var simpleDescription: String {
      switch self {
      case .spades:
          return "spades"
      case .hearts:
          return "hearts"
      case .diamonds:
          return "diamonds"
      case .clubs:
          return "clubs"
      }
  }

  var color: UIColor {
      switch self {
      case .spades:
          return .blackColor()
      case .hearts:
          return .redColor()
      case .diamonds:
          return .redColor()
      case .clubs:
          return .blackColor()
      }
  }

  var symbol: String {
      switch self {
      case .spades:
          return "♠"
      case .hearts:
          return "♥"
      case .diamonds:
          return "♦"
      case .clubs:
          return "♣"
      }
  }

  var bezierPath: UIBezierPath {
      switch self {
      case .spades:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .hearts:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .diamonds:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .clubs:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      }
  }
}

## Proposed solution

Support stored properties for enum cases just as each case were an
instance. Case properties are initialized block after each case
declaration.

enum Suit {
  let simpleDescription: String
  let color: UIColor
  let symbol: String
  let bezierPath: UIBezierPath

  case spades {
      simpleDescription = "spades"
      color = .blackColor()
      symbol = "♠"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case hearts {
      simpleDescription = "hearts"
      color = .redColor()
      symbol = "♥"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case diamonds {
      simpleDescription = "diamonds"
      color = .redColor()
      symbol = "♦"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case clubs {
      simpleDescription = "clubs"
      color = .blackColor()
      symbol = "♣"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }
}

let symbol = Suit.spades.symbol // "♠"

The proposed solution improves:
- Readability as cases are closer with their related data;
- Improves code maintainability as a case can be removed or added in one place;
- Improved performance as there is no need to recreate static values;
- ~30% less lines of code in given example.

## Detailed design

#### Stored properties

Enum stored properties are supported the same way they are supported
for structs can classes. Unlike enum associated values, stored
properties are static to case and are shared for the same case.

Properties are accessed:

let simpleDescription = Suit.spades.simpleDescription

Mutable properties can be set:

Suit.spades.simpleDescription = "new simple description"

#### Initialization

If enum has uninitialized stored property it must be initialized in a
block after each case declaration. The block work the same way as
struct initialization. At the end of initialization block all
properties must be initialized.

enum Suit {
  var simpleDescription: String

  case spades {
      simpleDescription = "spades"
  }
}

Initialization block can be combine with use of `rawValue`:

enum Suit: Int {
  var simpleDescription: String

  case spades = 1 {
      simpleDescription = "spades"
  }
}

or associated values of the case:

enum Suit {
  var simpleDescription: String

  case spades(Int) {
      simpleDescription = "spades"
  }
}

## Impact on existing code

Stored properties for enums are not currently not supported, so there
is no impact on existing code.

## Alternatives considered

- Use labeled tuple as `rawValue` of the enum case. This approach is
not compatible as it conflicts with intention of `rawValue` of Swift
enum;
- Use per case initializer like [Java
Enum](JDK 21 Documentation - Home).
Swift enum uses custom initializer syntax to setup instances, not
cases. So this approach is not suitable for Swift.

On Sun, May 29, 2016 at 3:42 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:
I think that's the case with enums. You're changing their current behaviour of only having stored values to one in which it's computed (even if only once and then stored). Enums are IMO something that have a static value you know beforehand and can count on. That's why I'm not fond of the accessor proposal. Otherwise I think we're transforming enums into a closed set of struct instances and one could do that already by using a private init.

On 29 May 2016, at 3:38 am, Jānis Kiršteins via swift-evolution <swift-evolution@swift.org> wrote:

I agree with the argument about use of "where", not replacing the raw
value and having some kind of initialization block. But I cannot see
why "accessors" concept is any better than stored properties to solve
the particular problem. The "accessors" concept has much wider scope
than enums and is a separate proposal.

On Sat, May 28, 2016 at 11:39 PM, Brent Royal-Gordon >>>>> <brent@architechies.com> wrote:

- Abusing rawValue is just that: an abuse.

My original proposal does not replace rawValue and is compatible with it.

`rawValue` has a different purpose from how you're using it. It's supposed to allow you to convert your type to some other *equivalent* type, like an equivalent integer or string. Moreover, it's supposed to allow you to *reconstruct* the instance from the raw value—remember, `RawRepresentable` has an `init(rawValue:)` requirement.

It is *not* supposed to be an ancillary bag of information on the side. You're cramming a square peg into a round hole here.

(Also, if you use `rawValue` for an ancillary bag of information, that means you *can't* use it on the same type for its intended purpose. For instance, you would not be able to assign numbers to your Planet enum's cases to help you serialize them or bridge them to Objective-C. That's not good.)

- Using `where` just doesn't match the use of `where` elsewhere in the language; everywhere else, it's some kind of condition.

It is also used in generic type constraints. Plus it reads like human
language: `case mercury where (mass: 3.303e+23, radius: 2.4397e6)`

But a generic constraint is also a type of condition: it specifies types which are permitted and divides them from types that are not.

This is *not* a condition. It's not anything like a condition. It's simply not consistent with anything else in the language.

- Dictionaries are the most straightforward way to handle this with the current language, but their lack of exhaustiveness checking is a problem.

Dictionaries can be used as workaround, but they cannot (lack of
exhaustiveness) solve the problem.

I agree that they're a halfway solution.

If `ValuesEnumerable` were to be accepted (and to have a generic requirement for its `allValues` property), you could write a Dictionary-like type which ensured at initialization time that it was exhaustive. That's not as good as compile time, but it's not bad—sort of a three-quarters solution.

     struct ExhaustiveDictionary<Key: Hashable, Value where Key: ValuesEnumerable>: Collection, DictionaryLiteralConvertible {
             private var dictionary: [Key: Value]

             init(dictionaryLiteral elements: (Key, Value)...) {
                     dictionary = [:]
                     for (k, v) in elements {
                             dictionary[k] = v
                     }

                     if dictionary.count != Key.allValues.count {
                             let missingKeys = Key.allValues.filter { dictionary[$0] == nil }
                             preconditionFailure("ExhaustiveDictionary is missing elements from \(Key.self): \(missingKeys)")
                     }
             }

             var startIndex: Dictionary.Index {
                     return dictionary.startIndex
             }
             var endIndex: Dictionary.Index {
                     return dictionary.endIndex
             }
             subscript(index: Dictionary.Index) -> (Key, Value) {
                     return dictionary[index]
             }
             func index(after i: Dictionary.Index) -> Dictionary.Index {
                     return dictionary.index(after: i)
             }

             subscript(key: Key) -> Value {
                     get { return dictionary[key]! }
                     set { dictionary[key] = newValue }
             }
     }

What I would do is borrow the "accessors" concept from the property behaviors proposal and extend it so that it supported both functions and variables.

Wouldn't accessor just be a redundant keyword here? Currently enums do
not support stored properties, so I guess there is no extra need to
mark properties with any special keyword.

The keyword is mainly to indicate the unusual syntax at the definition site, where you only have to specify the name of the accessor you're defining, not a `func` or `var` keyword, a return type, or even parameter names. (Like `willSet`, there's a default parameter name you can use.) Secondarily, though, I think it's helpful to indicate very explicitly that this is not an ordinary method or property definition, even if the compiler could perhaps sort things out without it. `accessor` is something a user can Google if they've never seen it before.

Property accessors might work for enums with associated values, but
not so well without them.

The two have nothing to do with each other. I showed your planets example, which has no associated values but uses accessors just fine.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

_______________________________________________
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

+1 to this behavior — one of the increasingly rare places where Java is nicer than Swift. This is the natural generalization / next step of the stored properties of this thread, and I can confirm what David said: it’s useful in practice.

P

···

On Jun 1, 2016, at 9:48 AM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

One thing I did often in Java (and miss in Swift) is using their enums to build state machines or implement command patterns for common commands.

Java enums are a sealed set of subclasses of the enum base type with (hopefully) immutable, singleton instances. So you can do fun things like:
- Define the base class constructor to be called to instantiate the subclasses, and declare the cases with the constructor arguments
- Declare a method on the base type and refine it on 1-2 particular cases
- Declare the enum implements an interface, and implement that interface separately for each case.
- Define data accessors specific to the type (such as the planets example above)

I'm not much fond of Java enums but then Java also doesn't have
structs so I think enums there were created to be a mix of structs and
enums and that's why you can do all the things you mention on your
list. That said:
- The tuple typed enum approach is the closest thing we discussed to
constructors like the ones in Java enums;
- I never knew one could do that in Java but I think tuples can hold
function types;
- I also never heard one can do that in Java but I begin to think what
you really want are structs here;
- Both approaches here provide that, but accessors would allow for
dynamic content to be generated, not static.

Also Swift already allow for functions to be declared in enums and I
think this would be a better place than accessor properties to place
code that will generate dynamic results.

L

···

On 1 June 2016 at 11:59, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

Sent from my iPad

On Jun 1, 2016, at 9:48 AM, David Waite via swift-evolution <swift-evolution@swift.org> wrote:

One thing I did often in Java (and miss in Swift) is using their enums to build state machines or implement command patterns for common commands.

Java enums are a sealed set of subclasses of the enum base type with (hopefully) immutable, singleton instances. So you can do fun things like:
- Define the base class constructor to be called to instantiate the subclasses, and declare the cases with the constructor arguments
- Declare a method on the base type and refine it on 1-2 particular cases
- Declare the enum implements an interface, and implement that interface separately for each case.
- Define data accessors specific to the type (such as the planets example above)

I like the SuitInfo approach below - with extensions, I think I can get close to what I have done in the past with Java. Maybe one day there is syntax to do this in the language directly

This is pretty similar to what we were discussing last week in this thread: [swift-evolution] [Pitch] Exhaustive pattern matching for protocols and classes

I'm planning to write up a proposal when I have time (hopefully in the next week or so).

-DW

On May 31, 2016, at 11:44 AM, Vladimir.S via swift-evolution <swift-evolution@swift.org> wrote:

I'm not sure about my opinion on this proposal, but I believe you should add this as alternatives of how we can have the similar features today without injecting stored properties into enums :

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  struct SuitInfo {
      let simpleDescription: String
      let color: UIColor
      let symbol: String
      let bezierPath: UIBezierPath
  }

  var info : SuitInfo {
      switch self {
      case .spades:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "spades",
              color: .blackColor(),
              symbol: ":spades:",
              bezierPath: path)

      case .hearts:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "hearts",
              color: .redColor(),
              symbol: ":heart:",
              bezierPath: path)

      case .diamonds:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "diamonds",
              color: .redColor(),
              symbol: ":diamonds:",
              bezierPath: path)

      case .clubs:
          let path = UIBezierPath()
          // omitted lines ...

          return SuitInfo(
              simpleDescription: "clubs",
              color: .blackColor(),
              symbol: ":clubs:",
              bezierPath: path)

      }
  }
}

and this:

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  struct SuitInfo {
      let simpleDescription: String
      let color: UIColor
      let symbol: String
      let bezierPath: UIBezierPath
  }

  static let spadesInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "spades",
          color: .blackColor(),
          symbol: ":spades:",
          bezierPath: path)
  }()

  static let heartsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "hearts",
          color: .redColor(),
          symbol: ":heart:",
          bezierPath: path)
  }()

  static let diamondsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "diamonds",
          color: .redColor(),
          symbol: ":diamonds:",
          bezierPath: path)
  }()

  static let clubsInfo : SuitInfo = {
      let path = UIBezierPath()
      // omitted lines ...

      return SuitInfo(
          simpleDescription: "clubs",
          color: .blackColor(),
          symbol: ":clubs:",
          bezierPath: path)
  }()

  var info : SuitInfo {
      switch self {
          case .spades: return Suit.spadesInfo
          case .hearts: return Suit.heartsInfo
          case .diamonds: return Suit.diamondsInfo
          case .clubs: return Suit.clubsInfo
      }
  }
}

On 31.05.2016 17:17, Jānis Kiršteins via swift-evolution wrote:
I wrote a proposal draft:

# Enum case stored properties

* Proposal: TBD
* Author: [Janis Kirsteins](https://github.com/kirsteins\)
* Status: TBD
* Review manager: TBD

## Introduction

This proposal allows each enum case to have stored properties.

## Motivation

Enums cases can have a lot of constant (or variable) static values
associated with it. For example, planets can have mass, radius, age,
closest star etc. Currently there is no way to set or get those values
easily.

Example below shows that is hard to read and manage static associated
values with each case. It is hard to add or remove case as it would
require to add or remove code in four different places in file. Also
static associated value like `UIBezierPath` is recreated each time the
property is computed while it's constant.

enum Suit {
  case spades
  case hearts
  case diamonds
  case clubs

  var simpleDescription: String {
      switch self {
      case .spades:
          return "spades"
      case .hearts:
          return "hearts"
      case .diamonds:
          return "diamonds"
      case .clubs:
          return "clubs"
      }
  }

  var color: UIColor {
      switch self {
      case .spades:
          return .blackColor()
      case .hearts:
          return .redColor()
      case .diamonds:
          return .redColor()
      case .clubs:
          return .blackColor()
      }
  }

  var symbol: String {
      switch self {
      case .spades:
          return "♠"
      case .hearts:
          return "♥"
      case .diamonds:
          return "♦"
      case .clubs:
          return "♣"
      }
  }

  var bezierPath: UIBezierPath {
      switch self {
      case .spades:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .hearts:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .diamonds:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      case .clubs:
          let path = UIBezierPath()
          // omitted lines ...
          return path
      }
  }
}

## Proposed solution

Support stored properties for enum cases just as each case were an
instance. Case properties are initialized block after each case
declaration.

enum Suit {
  let simpleDescription: String
  let color: UIColor
  let symbol: String
  let bezierPath: UIBezierPath

  case spades {
      simpleDescription = "spades"
      color = .blackColor()
      symbol = "♠"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case hearts {
      simpleDescription = "hearts"
      color = .redColor()
      symbol = "♥"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case diamonds {
      simpleDescription = "diamonds"
      color = .redColor()
      symbol = "♦"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }

  case clubs {
      simpleDescription = "clubs"
      color = .blackColor()
      symbol = "♣"
      let bezierPath = UIBezierPath()
      // omitted lines ...
      self.bezierPath = bezierPath
  }
}

let symbol = Suit.spades.symbol // "♠"

The proposed solution improves:
- Readability as cases are closer with their related data;
- Improves code maintainability as a case can be removed or added in one place;
- Improved performance as there is no need to recreate static values;
- ~30% less lines of code in given example.

## Detailed design

#### Stored properties

Enum stored properties are supported the same way they are supported
for structs can classes. Unlike enum associated values, stored
properties are static to case and are shared for the same case.

Properties are accessed:

let simpleDescription = Suit.spades.simpleDescription

Mutable properties can be set:

Suit.spades.simpleDescription = "new simple description"

#### Initialization

If enum has uninitialized stored property it must be initialized in a
block after each case declaration. The block work the same way as
struct initialization. At the end of initialization block all
properties must be initialized.

enum Suit {
  var simpleDescription: String

  case spades {
      simpleDescription = "spades"
  }
}

Initialization block can be combine with use of `rawValue`:

enum Suit: Int {
  var simpleDescription: String

  case spades = 1 {
      simpleDescription = "spades"
  }
}

or associated values of the case:

enum Suit {
  var simpleDescription: String

  case spades(Int) {
      simpleDescription = "spades"
  }
}

## Impact on existing code

Stored properties for enums are not currently not supported, so there
is no impact on existing code.

## Alternatives considered

- Use labeled tuple as `rawValue` of the enum case. This approach is
not compatible as it conflicts with intention of `rawValue` of Swift
enum;
- Use per case initializer like [Java
Enum](JDK 21 Documentation - Home).
Swift enum uses custom initializer syntax to setup instances, not
cases. So this approach is not suitable for Swift.

On Sun, May 29, 2016 at 3:42 PM, Leonardo Pessoa <me@lmpessoa.com> wrote:
I think that's the case with enums. You're changing their current behaviour of only having stored values to one in which it's computed (even if only once and then stored). Enums are IMO something that have a static value you know beforehand and can count on. That's why I'm not fond of the accessor proposal. Otherwise I think we're transforming enums into a closed set of struct instances and one could do that already by using a private init.

On 29 May 2016, at 3:38 am, Jānis Kiršteins via swift-evolution <swift-evolution@swift.org> wrote:

I agree with the argument about use of "where", not replacing the raw
value and having some kind of initialization block. But I cannot see
why "accessors" concept is any better than stored properties to solve
the particular problem. The "accessors" concept has much wider scope
than enums and is a separate proposal.

On Sat, May 28, 2016 at 11:39 PM, Brent Royal-Gordon >>>>>> <brent@architechies.com> wrote:

- Abusing rawValue is just that: an abuse.

My original proposal does not replace rawValue and is compatible with it.

`rawValue` has a different purpose from how you're using it. It's supposed to allow you to convert your type to some other *equivalent* type, like an equivalent integer or string. Moreover, it's supposed to allow you to *reconstruct* the instance from the raw value—remember, `RawRepresentable` has an `init(rawValue:)` requirement.

It is *not* supposed to be an ancillary bag of information on the side. You're cramming a square peg into a round hole here.

(Also, if you use `rawValue` for an ancillary bag of information, that means you *can't* use it on the same type for its intended purpose. For instance, you would not be able to assign numbers to your Planet enum's cases to help you serialize them or bridge them to Objective-C. That's not good.)

- Using `where` just doesn't match the use of `where` elsewhere in the language; everywhere else, it's some kind of condition.

It is also used in generic type constraints. Plus it reads like human
language: `case mercury where (mass: 3.303e+23, radius: 2.4397e6)`

But a generic constraint is also a type of condition: it specifies types which are permitted and divides them from types that are not.

This is *not* a condition. It's not anything like a condition. It's simply not consistent with anything else in the language.

- Dictionaries are the most straightforward way to handle this with the current language, but their lack of exhaustiveness checking is a problem.

Dictionaries can be used as workaround, but they cannot (lack of
exhaustiveness) solve the problem.

I agree that they're a halfway solution.

If `ValuesEnumerable` were to be accepted (and to have a generic requirement for its `allValues` property), you could write a Dictionary-like type which ensured at initialization time that it was exhaustive. That's not as good as compile time, but it's not bad—sort of a three-quarters solution.

     struct ExhaustiveDictionary<Key: Hashable, Value where Key: ValuesEnumerable>: Collection, DictionaryLiteralConvertible {
             private var dictionary: [Key: Value]

             init(dictionaryLiteral elements: (Key, Value)...) {
                     dictionary = [:]
                     for (k, v) in elements {
                             dictionary[k] = v
                     }

                     if dictionary.count != Key.allValues.count {
                             let missingKeys = Key.allValues.filter { dictionary[$0] == nil }
                             preconditionFailure("ExhaustiveDictionary is missing elements from \(Key.self): \(missingKeys)")
                     }
             }

             var startIndex: Dictionary.Index {
                     return dictionary.startIndex
             }
             var endIndex: Dictionary.Index {
                     return dictionary.endIndex
             }
             subscript(index: Dictionary.Index) -> (Key, Value) {
                     return dictionary[index]
             }
             func index(after i: Dictionary.Index) -> Dictionary.Index {
                     return dictionary.index(after: i)
             }

             subscript(key: Key) -> Value {
                     get { return dictionary[key]! }
                     set { dictionary[key] = newValue }
             }
     }

What I would do is borrow the "accessors" concept from the property behaviors proposal and extend it so that it supported both functions and variables.

Wouldn't accessor just be a redundant keyword here? Currently enums do
not support stored properties, so I guess there is no extra need to
mark properties with any special keyword.

The keyword is mainly to indicate the unusual syntax at the definition site, where you only have to specify the name of the accessor you're defining, not a `func` or `var` keyword, a return type, or even parameter names. (Like `willSet`, there's a default parameter name you can use.) Secondarily, though, I think it's helpful to indicate very explicitly that this is not an ordinary method or property definition, even if the compiler could perhaps sort things out without it. `accessor` is something a user can Google if they've never seen it before.

Property accessors might work for enums with associated values, but
not so well without them.

The two have nothing to do with each other. I showed your planets example, which has no associated values but uses accessors just fine.

--
Brent Royal-Gordon
Architechies

_______________________________________________
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

_______________________________________________
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

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

Hello David,

Could you elaborate on this more? Seeing the possibilities of FSM's in
Swift using its powerful enum and case pattern matching was one of the
moments in which Swift started increasing its allure factor ;).

Part 1 (background and theory):
http://www.figure.ink/blog/2015/1/31/swift-state-machines-part-1

Part 2 (start of the implementation):

Part 3:

Part 4:

Final gist: Updated State Machine with Untangled Transitions and Behaviors · GitHub

···

On Wed, Jun 1, 2016 at 3:48 PM, David Waite via swift-evolution < swift-evolution@swift.org> wrote:

One thing I did often in Java (and miss in Swift) is using their enums to
build state machines or implement command patterns for common commands.

Java enums are a sealed set of subclasses of the enum base type with
(hopefully) immutable, singleton instances. So you can do fun things like:
- Define the base class constructor to be called to instantiate the
subclasses, and declare the cases with the constructor arguments
- Declare a method on the base type and refine it on 1-2 particular cases
- Declare the enum implements an interface, and implement that interface
separately for each case.
- Define data accessors specific to the type (such as the planets example
above)

I like the SuitInfo approach below - with extensions, I think I can get
close to what I have done in the past with Java. Maybe one day there is
syntax to do this in the language directly

-DW

> On May 31, 2016, at 11:44 AM, Vladimir.S via swift-evolution < > swift-evolution@swift.org> wrote:
>
> I'm not sure about my opinion on this proposal, but I believe you should
add this as alternatives of how we can have the similar features today
without injecting stored properties into enums :
>
> enum Suit {
> case spades
> case hearts
> case diamonds
> case clubs
>
> struct SuitInfo {
> let simpleDescription: String
> let color: UIColor
> let symbol: String
> let bezierPath: UIBezierPath
> }
>
> var info : SuitInfo {
> switch self {
> case .spades:
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "spades",
> color: .blackColor(),
> symbol: ":spades:",
> bezierPath: path)
>
> case .hearts:
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "hearts",
> color: .redColor(),
> symbol: ":heart:",
> bezierPath: path)
>
> case .diamonds:
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "diamonds",
> color: .redColor(),
> symbol: ":diamonds:",
> bezierPath: path)
>
> case .clubs:
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "clubs",
> color: .blackColor(),
> symbol: ":clubs:",
> bezierPath: path)
>
> }
> }
> }
>
> and this:
>
> enum Suit {
> case spades
> case hearts
> case diamonds
> case clubs
>
> struct SuitInfo {
> let simpleDescription: String
> let color: UIColor
> let symbol: String
> let bezierPath: UIBezierPath
> }
>
> static let spadesInfo : SuitInfo = {
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "spades",
> color: .blackColor(),
> symbol: ":spades:",
> bezierPath: path)
> }()
>
> static let heartsInfo : SuitInfo = {
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "hearts",
> color: .redColor(),
> symbol: ":heart:",
> bezierPath: path)
> }()
>
> static let diamondsInfo : SuitInfo = {
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "diamonds",
> color: .redColor(),
> symbol: ":diamonds:",
> bezierPath: path)
> }()
>
> static let clubsInfo : SuitInfo = {
> let path = UIBezierPath()
> // omitted lines ...
>
> return SuitInfo(
> simpleDescription: "clubs",
> color: .blackColor(),
> symbol: ":clubs:",
> bezierPath: path)
> }()
>
>
> var info : SuitInfo {
> switch self {
> case .spades: return Suit.spadesInfo
> case .hearts: return Suit.heartsInfo
> case .diamonds: return Suit.diamondsInfo
> case .clubs: return Suit.clubsInfo
> }
> }
> }
>
>
> On 31.05.2016 17:17, Jānis Kiršteins via swift-evolution wrote:
>> I wrote a proposal draft:
>>
>> # Enum case stored properties
>>
>> * Proposal: TBD
>> * Author: [Janis Kirsteins](https://github.com/kirsteins\)
>> * Status: TBD
>> * Review manager: TBD
>>
>> ## Introduction
>>
>> This proposal allows each enum case to have stored properties.
>>
>> ## Motivation
>>
>> Enums cases can have a lot of constant (or variable) static values
>> associated with it. For example, planets can have mass, radius, age,
>> closest star etc. Currently there is no way to set or get those values
>> easily.
>>
>> Example below shows that is hard to read and manage static associated
>> values with each case. It is hard to add or remove case as it would
>> require to add or remove code in four different places in file. Also
>> static associated value like `UIBezierPath` is recreated each time the
>> property is computed while it's constant.
>>
>> ```swift
>> enum Suit {
>> case spades
>> case hearts
>> case diamonds
>> case clubs
>>
>> var simpleDescription: String {
>> switch self {
>> case .spades:
>> return "spades"
>> case .hearts:
>> return "hearts"
>> case .diamonds:
>> return "diamonds"
>> case .clubs:
>> return "clubs"
>> }
>> }
>>
>> var color: UIColor {
>> switch self {
>> case .spades:
>> return .blackColor()
>> case .hearts:
>> return .redColor()
>> case .diamonds:
>> return .redColor()
>> case .clubs:
>> return .blackColor()
>> }
>> }
>>
>> var symbol: String {
>> switch self {
>> case .spades:
>> return ":spades:"
>> case .hearts:
>> return ":heart:"
>> case .diamonds:
>> return ":diamonds:"
>> case .clubs:
>> return ":clubs:"
>> }
>> }
>>
>> var bezierPath: UIBezierPath {
>> switch self {
>> case .spades:
>> let path = UIBezierPath()
>> // omitted lines ...
>> return path
>> case .hearts:
>> let path = UIBezierPath()
>> // omitted lines ...
>> return path
>> case .diamonds:
>> let path = UIBezierPath()
>> // omitted lines ...
>> return path
>> case .clubs:
>> let path = UIBezierPath()
>> // omitted lines ...
>> return path
>> }
>> }
>> }
>> ```
>>
>> ## Proposed solution
>>
>> Support stored properties for enum cases just as each case were an
>> instance. Case properties are initialized block after each case
>> declaration.
>>
>> ```swift
>> enum Suit {
>> let simpleDescription: String
>> let color: UIColor
>> let symbol: String
>> let bezierPath: UIBezierPath
>>
>> case spades {
>> simpleDescription = "spades"
>> color = .blackColor()
>> symbol = ":spades:"
>> let bezierPath = UIBezierPath()
>> // omitted lines ...
>> self.bezierPath = bezierPath
>> }
>>
>> case hearts {
>> simpleDescription = "hearts"
>> color = .redColor()
>> symbol = ":heart:"
>> let bezierPath = UIBezierPath()
>> // omitted lines ...
>> self.bezierPath = bezierPath
>> }
>>
>> case diamonds {
>> simpleDescription = "diamonds"
>> color = .redColor()
>> symbol = ":diamonds:"
>> let bezierPath = UIBezierPath()
>> // omitted lines ...
>> self.bezierPath = bezierPath
>> }
>>
>> case clubs {
>> simpleDescription = "clubs"
>> color = .blackColor()
>> symbol = ":clubs:"
>> let bezierPath = UIBezierPath()
>> // omitted lines ...
>> self.bezierPath = bezierPath
>> }
>> }
>>
>> let symbol = Suit.spades.symbol // ":spades:"
>> ```
>>
>> The proposed solution improves:
>> - Readability as cases are closer with their related data;
>> - Improves code maintainability as a case can be removed or added in
one place;
>> - Improved performance as there is no need to recreate static values;
>> - ~30% less lines of code in given example.
>>
>> ## Detailed design
>>
>> #### Stored properties
>>
>> Enum stored properties are supported the same way they are supported
>> for structs can classes. Unlike enum associated values, stored
>> properties are static to case and are shared for the same case.
>>
>> Properties are accessed:
>> ```swift
>> let simpleDescription = Suit.spades.simpleDescription
>> ```
>>
>> Mutable properties can be set:
>> ```swift
>> Suit.spades.simpleDescription = "new simple description"
>> ```
>>
>> #### Initialization
>>
>> If enum has uninitialized stored property it must be initialized in a
>> block after each case declaration. The block work the same way as
>> struct initialization. At the end of initialization block all
>> properties must be initialized.
>>
>> ```swift
>> enum Suit {
>> var simpleDescription: String
>>
>> case spades {
>> simpleDescription = "spades"
>> }
>> }
>> ```
>>
>> Initialization block can be combine with use of `rawValue`:
>>
>> ```swift
>> enum Suit: Int {
>> var simpleDescription: String
>>
>> case spades = 1 {
>> simpleDescription = "spades"
>> }
>> }
>> ```
>> or associated values of the case:
>>
>> ```swift
>> enum Suit {
>> var simpleDescription: String
>>
>> case spades(Int) {
>> simpleDescription = "spades"
>> }
>> }
>> ```
>>
>> ## Impact on existing code
>>
>> Stored properties for enums are not currently not supported, so there
>> is no impact on existing code.
>>
>> ## Alternatives considered
>>
>> - Use labeled tuple as `rawValue` of the enum case. This approach is
>> not compatible as it conflicts with intention of `rawValue` of Swift
>> enum;
>> - Use per case initializer like [Java
>> Enum](JDK 21 Documentation - Home).
>> Swift enum uses custom initializer syntax to setup instances, not
>> cases. So this approach is not suitable for Swift.
>>
>>
>> On Sun, May 29, 2016 at 3:42 PM, Leonardo Pessoa <me@lmpessoa.com> > wrote:
>>> I think that's the case with enums. You're changing their current
behaviour of only having stored values to one in which it's computed (even
if only once and then stored). Enums are IMO something that have a static
value you know beforehand and can count on. That's why I'm not fond of the
accessor proposal. Otherwise I think we're transforming enums into a closed
set of struct instances and one could do that already by using a private
init.
>>>
>>>
>>>> On 29 May 2016, at 3:38 am, Jānis Kiršteins via swift-evolution < > swift-evolution@swift.org> wrote:
>>>>
>>>> I agree with the argument about use of "where", not replacing the raw
>>>> value and having some kind of initialization block. But I cannot see
>>>> why "accessors" concept is any better than stored properties to solve
>>>> the particular problem. The "accessors" concept has much wider scope
>>>> than enums and is a separate proposal.
>>>>
>>>> On Sat, May 28, 2016 at 11:39 PM, Brent Royal-Gordon > >>>> <brent@architechies.com> wrote:
>>>>>>> - Abusing rawValue is just that: an abuse.
>>>>>>
>>>>>> My original proposal does not replace rawValue and is compatible
with it.
>>>>>
>>>>> `rawValue` has a different purpose from how you're using it. It's
supposed to allow you to convert your type to some other *equivalent* type,
like an equivalent integer or string. Moreover, it's supposed to allow you
to *reconstruct* the instance from the raw value—remember,
`RawRepresentable` has an `init(rawValue:)` requirement.
>>>>>
>>>>> It is *not* supposed to be an ancillary bag of information on the
side. You're cramming a square peg into a round hole here.
>>>>>
>>>>> (Also, if you use `rawValue` for an ancillary bag of information,
that means you *can't* use it on the same type for its intended purpose.
For instance, you would not be able to assign numbers to your Planet enum's
cases to help you serialize them or bridge them to Objective-C. That's not
good.)
>>>>>
>>>>>>> - Using `where` just doesn't match the use of `where` elsewhere in
the language; everywhere else, it's some kind of condition.
>>>>>>
>>>>>> It is also used in generic type constraints. Plus it reads like
human
>>>>>> language: `case mercury where (mass: 3.303e+23, radius: 2.4397e6)`
>>>>>
>>>>> But a generic constraint is also a type of condition: it specifies
types which are permitted and divides them from types that are not.
>>>>>
>>>>> This is *not* a condition. It's not anything like a condition. It's
simply not consistent with anything else in the language.
>>>>>
>>>>>>> - Dictionaries are the most straightforward way to handle this
with the current language, but their lack of exhaustiveness checking is a
problem.
>>>>>>
>>>>>> Dictionaries can be used as workaround, but they cannot (lack of
>>>>>> exhaustiveness) solve the problem.
>>>>>
>>>>> I agree that they're a halfway solution.
>>>>>
>>>>> If `ValuesEnumerable` were to be accepted (and to have a generic
requirement for its `allValues` property), you could write a
Dictionary-like type which ensured at initialization time that it was
exhaustive. That's not as good as compile time, but it's not bad—sort of a
three-quarters solution.
>>>>>
>>>>> struct ExhaustiveDictionary<Key: Hashable, Value where Key:
>: Collection, DictionaryLiteralConvertible {
>>>>> private var dictionary: [Key: Value]
>>>>>
>>>>> init(dictionaryLiteral elements: (Key, Value)...) {
>>>>> dictionary = [:]
>>>>> for (k, v) in elements {
>>>>> dictionary[k] = v
>>>>> }
>>>>>
>>>>> if dictionary.count != Key.allValues.count {
>>>>> let missingKeys = Key.allValues.filter
{ dictionary[$0] == nil }
>>>>>
preconditionFailure("ExhaustiveDictionary is missing elements from
\(Key.self): \(missingKeys)")
>>>>> }
>>>>> }
>>>>>
>>>>> var startIndex: Dictionary.Index {
>>>>> return dictionary.startIndex
>>>>> }
>>>>> var endIndex: Dictionary.Index {
>>>>> return dictionary.endIndex
>>>>> }
>>>>> subscript(index: Dictionary.Index) -> (Key, Value) {
>>>>> return dictionary[index]
>>>>> }
>>>>> func index(after i: Dictionary.Index) ->
Dictionary.Index {
>>>>> return dictionary.index(after: i)
>>>>> }
>>>>>
>>>>> subscript(key: Key) -> Value {
>>>>> get { return dictionary[key]! }
>>>>> set { dictionary[key] = newValue }
>>>>> }
>>>>> }
>>>>>
>>>>>>> What I would do is borrow the "accessors" concept from the
property behaviors proposal and extend it so that it supported both
functions and variables.
>>>>>>
>>>>>> Wouldn't accessor just be a redundant keyword here? Currently enums
do
>>>>>> not support stored properties, so I guess there is no extra need to
>>>>>> mark properties with any special keyword.
>>>>>
>>>>> The keyword is mainly to indicate the unusual syntax at the
definition site, where you only have to specify the name of the accessor
you're defining, not a `func` or `var` keyword, a return type, or even
parameter names. (Like `willSet`, there's a default parameter name you can
use.) Secondarily, though, I think it's helpful to indicate very explicitly
that this is not an ordinary method or property definition, even if the
compiler could perhaps sort things out without it. `accessor` is something
a user can Google if they've never seen it before.
>>>>>
>>>>>> Property accessors might work for enums with associated values, but
>>>>>> not so well without them.
>>>>>
>>>>> The two have nothing to do with each other. I showed your planets
example, which has no associated values but uses accessors just fine.
>>>>>
>>>>> --
>>>>> Brent Royal-Gordon
>>>>> Architechies
>>>>>
>>>> _______________________________________________
>>>> 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
>>
> _______________________________________________
> 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

As stated before it supposed to be per case initialization. You cannot
really have this analogy with other types as they have type and
instance while enums have type, case and instance. But consider this:

struct Struct {
    static let bezierPath: UIBezierPath // shared

    static func initialize() {
        bezierPath = UIBezierPath()
    }
}

···

On Thu, Jun 2, 2016 at 12:18 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

UIBezierPath is shared for all instances of the enum case. So stored
properties are stored per case, not per instance (you have associated
values for per instance values).

that isn't really what this syntax suggests is happening

Please explain what makes you think that way.

Because you wrote `let bezierPath = UIBezierPath()` in the middle of a type definition, and in all other types, you would get a new bezier path for each instance.

        struct Struct {
                let bezierPath = UIBezierPath() // per instance
        }
        class Class {
                let bezierPath = UIBezierPath() // per instance
        }
        func function() {
                let bezierPath = UIBezierPath() // per call
        }
        enum Enum {
                case aCase {
                        let bezierPath = UIBezierPath() // shared?!?!
                }
        }

--
Brent Royal-Gordon
Architechies

As stated before it supposed to be per case initialization. You cannot
really have this analogy with other types as they have type and
instance while enums have type, case and instance.

No. If structs have just type and instance, then so do enums.

Cases in enums are analogous to stored properties in structs: they are a means of organizing and representing concrete storage. They are not first-class entities in the way that types and instances are. Much mischief comes from thinking of cases as pseudo-types, or as some sort of peer to a type.

But consider this:

struct Struct {
   static let bezierPath: UIBezierPath // shared

   static func initialize() {
       bezierPath = UIBezierPath()
   }
}

Yes, because there's a `static` keyword on that declaration. That marks it as something different from an ordinary `let`. Similarly, part of the idea of my use of accessors is that the `accessor` keyword marks it as something different from an ordinary `var`.

(Also, you shouldn't use `initialize()` in Swift; you should set the variable directly. Also also, I'm pretty sure that wouldn't work at all, because `initialize()` is a normal method, not an initializer, and `bezierPath` is a constant.)

···

--
Brent Royal-Gordon
Architechies

I think you misunderstood my proposed syntax. To clarify:

enum Suit {
    let bezierPath: UIBezierPath // Stored property declaration

    case spades {
        let bezierPath = UIBezierPath() // Declare and initialize and
local variable, this is not stored property declaration
        // add drawing commands to bezierPath
        self.bezierPath = bezierPath // Initialize stored property
with local variable. Stored property is shared among cases
    }
}

I agree that cases should not be treated as pseudo-type, I am not
proposing that. What I am proposing is the that enum instance
behaviour and data can be very dependent of it case. And that there
should be easier and clearer ways to configure that using stored
properties.

···

On Thu, Jun 2, 2016 at 10:26 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

As stated before it supposed to be per case initialization. You cannot
really have this analogy with other types as they have type and
instance while enums have type, case and instance.

No. If structs have just type and instance, then so do enums.

Cases in enums are analogous to stored properties in structs: they are a means of organizing and representing concrete storage. They are not first-class entities in the way that types and instances are. Much mischief comes from thinking of cases as pseudo-types, or as some sort of peer to a type.

But consider this:

struct Struct {
   static let bezierPath: UIBezierPath // shared

   static func initialize() {
       bezierPath = UIBezierPath()
   }
}

Yes, because there's a `static` keyword on that declaration. That marks it as something different from an ordinary `let`. Similarly, part of the idea of my use of accessors is that the `accessor` keyword marks it as something different from an ordinary `var`.

(Also, you shouldn't use `initialize()` in Swift; you should set the variable directly. Also also, I'm pretty sure that wouldn't work at all, because `initialize()` is a normal method, not an initializer, and `bezierPath` is a constant.)

--
Brent Royal-Gordon
Architechies