[swift-evolution] [Proposal] Enums with stored properties

Xiaodi Wu xiaodi.wu at gmail.com
Wed Oct 12 10:12:35 CDT 2016


On Wed, Oct 12, 2016 at 10:07 AM, Karl via swift-evolution <
swift-evolution at swift.org> wrote:

> Not at all - his proposal looks like the enum cases have an associated
> value, when that is exactly what you _don’t_ want. It’s wasted storage
> because they have a handful of known values.
>
> It’s a PITA, I get it, I go through it all the time, too; but really this
> is the very definition of a computed property. There is nothing to be
> stored here. Meanwhile, something like:
>
> enum Something {
>    case oneThing(UIView)
>    case anotherThing(Error)
>    case yetAnotherThing(Int)
> }
>
> …which is dangerously similar to Braeden’s example, really does store an
> instance of UIView or Error or Int along with it. The size of the value is
> the maximum of those, plus a couple of bits to record which case it is and
> what the type of the payload is.
>
> Confusing those things just because you don’t like writing switch
> statements would be bad, IMO. It’s not that much code, and once you’ve done
> a few of them you can make it quite compact. If you have a boatload of
> associated values, wrap them in a struct.
> Some more convenient generated accessors for the associated data might be
> nice, but that’s been proposed and discussed to death. Others who have
> followed the lists more closely can maybe tell you why we don’t have an
> accepted proposal for it.
>

I agree with Karl on this. There should be clarity here as to what's
proposed. If it's a change to how enums are laid out in memory, then you'll
need to show we're not sacrificing performance/size in the overwhelmingly
more common use cases, and why the extra storage is useful in the first
place; if it's syntactic sugar, that has already been proposed multiple
times and really isn't in scope for this phase of Swift 4--nor does it
really enable any new use cases not possible now.


> - Karl
>
> > On 12 Oct 2016, at 13:52, Rien <Rien at Balancingrock.nl> wrote:
> >
> > I read Braeden’s example such that this proposal is in reality “just”
> syntactic sugar. AFAIAC it does not change how enums are implemented after
> compilation.
> >
> > Like sugar, it makes working with enums clearer and therefore easier.
> All initialisation values are defined right there with the ‘case’ instead
> of hidden in a tree of multiple ‘var’s.
> > While I was sceptical about this proposal, Braeden’s example makes it a
> +1.
> >
> > Rien.
> >
> > Btw: I made the almost identical suggestion you did ;-)
> >
> >
> >> On 12 Oct 2016, at 13:31, Karl <razielim at gmail.com> wrote:
> >>
> >> I very much disagree with the proposal, and all of the things
> supporting it (like deriving enums from other types and whatnot). I think
> you need to take a step up from caring about whether it’s a struct or enum
> and think about what you are trying to model; that will guide you towards
> the correct type(s) to use.
> >>
> >> You have only shown a handful of fixed size values, so I would suggest
> a computed property in your case:
> >>
> >> enum FixedSize {
> >> case small
> >> case medium
> >> case large
> >>
> >> struct Size { let width : Int; let height: Int }
> >>
> >> var size : Size {
> >>   switch self {
> >>       case .small: return Size(width: 30, height: 30)
> >>       // … etc
> >>   }
> >> }
> >> }
> >>
> >> There is no need for these sizes to be stored at all. If you want them
> baked in to your enum’s values, clearly you expect them to be specific
> values. It’s more efficient to just drop the stored data altogether in this
> case; this enum will get lowered in to single byte, which is more efficient
> to store and transport.
> >>
> >> Karl
> >>
> >>> On 12 Oct 2016, at 13:15, Mateusz Malczak via swift-evolution <
> swift-evolution at swift.org> wrote:
> >>>
> >>>> Mateusz, you lost me with “store some extra data”.
> >>>> Does that mean something extra besides the code that Braeden
> suggested?
> >>>
> >>> What I meant by “store some extra data” was, to be able to define
> >>> immutable properties of any type, as a part of enum instead of
> >>> defining getters witch switches. I think Braeden example explains the
> >>> whole idea of that proposal.
> >>>
> >>> --
> >>> | Mateusz Malczak
> >>>
> >>>
> >>> 2016-10-12 8:42 GMT+02:00 Rien <Rien at balancingrock.nl>:
> >>>> I’d give a +1 for the suggestion of Braeden.
> >>>>
> >>>> Mateusz, you lost me with “store some extra data”.
> >>>> Does that mean something extra besides the code that Braeden
> suggested?
> >>>>
> >>>> Rien.
> >>>>
> >>>>> On 12 Oct 2016, at 00:13, Mateusz Malczak via swift-evolution <
> swift-evolution at swift.org> wrote:
> >>>>>
> >>>>> That's exactly what this proposal is about. I would like to
> >>>>> keep all enum properties but add an extra feature, so that enums can
> >>>>> store some extra data.
> >>>>> --
> >>>>> | Mateusz Malczak
> >>>>> +-------------------------------
> >>>>> | mateusz at malczak.info
> >>>>> | http://malczak.info
> >>>>>
> >>>>>
> >>>>> 2016-10-11 23:42 GMT+02:00 Braeden Profile <jhaezhyr12 at gmail.com>:
> >>>>>> So, just to recap, the proposed solution is to help enums expose
> associated
> >>>>>> values via properties, and is not to create enums that are open to
> extra
> >>>>>> unnamed cases (RectSize(width:0,height:10))?  What I see is that
> enums would
> >>>>>> still maintain their standing where an instance is just a selection
> of a
> >>>>>> finite number of options, possibly with data attached.  In proposal
> 1, we
> >>>>>> want some sort of syntax where this…
> >>>>>>
> >>>>>> enum RectSize
> >>>>>> {
> >>>>>> let height:Int
> >>>>>> let width:Int
> >>>>>> case small(width: 30, height: 30)
> >>>>>> case medium(width: 60, height: 60)
> >>>>>> case large(width: 120, height: 120)
> >>>>>> }
> >>>>>>
> >>>>>> …is syntactically just like writing this…
> >>>>>>
> >>>>>> enum RectSize
> >>>>>> {
> >>>>>> case small
> >>>>>> case medium
> >>>>>> case large
> >>>>>> var height:Int
> >>>>>> {
> >>>>>>   switch self
> >>>>>>   {
> >>>>>>      case .small: return 30
> >>>>>>      case .medium: return 60
> >>>>>>      case .large: return 90
> >>>>>>   }
> >>>>>> }
> >>>>>> let width:Int
> >>>>>> {
> >>>>>>   switch self
> >>>>>>   {
> >>>>>>      case .small: return 30
> >>>>>>      case .medium: return 60
> >>>>>>      case .large: return 90
> >>>>>>   }
> >>>>>> }
> >>>>>> }
> >>>>>>
> >>>>>> …right?  That way, you can write this:
> >>>>>>
> >>>>>> var size: RectSize = .small
> >>>>>> size.height == 30 // true
> >>>>>> size.rawValue // Error:  RectSizes has no property `rawValue`.
> >>>>>> size.height = 40 // Error:  `height` is immutable
> >>>>>> size = .medium
> >>>>>>
> >>>>>> I think we were also (separately) proposing to extend `rawValue` to
> take all
> >>>>>> kinds of statically known values, like structs or tuples.  Doing
> that would
> >>>>>> accomplish much of the same thing.
> >>>>>>
> >>>>>> Someone fact-check me here!  I really do think something like this
> would be
> >>>>>> a good idea, if we could get the right syntax.
> >>>>>>
> >>>>>> On Oct 11, 2016, at 7:06 AM, Mateusz Malczak via swift-evolution
> >>>>>> <swift-evolution at swift.org> wrote:
> >>>>>>
> >>>>>> Hi,
> >>>>>> I think we are here discussing two different aspects of introducing
> >>>>>> this new feature - code syntax and underlying implementation.
> >>>>>> In terms of code syntax I would go with first proposal as it seems
> to
> >>>>>> me the simplest approach. When it comes to underlying
> implementation,
> >>>>>> I can imagine that during compilation internal struct is created, as
> >>>>>> well as any required property getters. This way you could get a
> >>>>>> variation of rawValue implementation, at least from theoretical
> point
> >>>>>> of view :D
> >>>>>>
> >>>>>> --
> >>>>>> | Mateusz Malczak
> >>>>>> +-------------------------------
> >>>>>> | mateusz at malczak.info
> >>>>>> | http://malczak.info
> >>>>>>
> >>>>>>
> >>>>>> 2016-10-10 23:42 GMT+02:00 Haravikk <swift-evolution at haravikk.me>:
> >>>>>>
> >>>>>>
> >>>>>> On 10 Oct 2016, at 20:34, Mateusz Malczak <mateusz at malczak.info>
> wrote:
> >>>>>>
> >>>>>> I know, but what I'm saying is that this problem could be solved in
> the
> >>>>>> multiple values case by allowing tuples as raw values for enums,
> since that
> >>>>>> would allow you to specify both width and height. So it'd look
> something
> >>>>>> like this:
> >>>>>>
> >>>>>>
> >>>>>> We have three different possible solution
> >>>>>> 1. stored properties defined as part of enumeration type
> >>>>>> enum RectSizes: MyRect
> >>>>>> {
> >>>>>> let height:Int
> >>>>>> let width:Int
> >>>>>> case Small(width: 30, height: 30)
> >>>>>> case Medium(width: 60, height: 60)
> >>>>>> case Large(width: 120, height: 120)
> >>>>>> }
> >>>>>>
> >>>>>> 2. struct as rawValue
> >>>>>> struct MyRect
> >>>>>> {
> >>>>>> var height:Int
> >>>>>> var width:Int
> >>>>>> var area:Int {return height:Int*width}
> >>>>>> }
> >>>>>>
> >>>>>> enum RectSizes: MyRect
> >>>>>> {
> >>>>>> case Small(30,30)
> >>>>>> case Medium(60,60)
> >>>>>> case Large(120,120)
> >>>>>> }
> >>>>>>
> >>>>>> 3. tuples as rawValue
> >>>>>> enum Format : (width:Int, height:Int) {
> >>>>>> case small(30, 30)
> >>>>>> case medium(60, 60)
> >>>>>> case large(120, 120)
> >>>>>>
> >>>>>> var width:Int { return self.rawValue.width }
> >>>>>> var height:Int { return self.rawValue.height }
> >>>>>> }
> >>>>>>
> >>>>>> Solutions 2 and 3 are quire similar, to get value of a stored
> property
> >>>>>> we need to use rawValue or define value getters. In addition in
> >>>>>> solution 2 we define an additional data type just to be used as an
> >>>>>> enumeration type rawValue type. In my opinion, first approach would
> be
> >>>>>> a best solution, type definition is clear and self-explanatory
> because
> >>>>>> it is similar to how enums/classes are defined.
> >>>>>>
> >>>>>>
> >>>>>> --
> >>>>>> | Mateusz Malczak
> >>>>>>
> >>>>>>
> >>>>>> Actually I'd say your option 2 here is more similar to option 1
> (you seem to
> >>>>>> be using a struct to define the stored properties instead). The
> issue here
> >>>>>> is that storing properties conflicts with what you're actually
> doing, which
> >>>>>> is storing case-specific values, which is what rawValue already
> does, it's
> >>>>>> just too limited for your current use-case (multiple values).
> >>>>>>
> >>>>>> The complete solution would be to introduce the concept of tuples as
> >>>>>> literals (even though they can't currently conform to types); this
> would
> >>>>>> make it a lot easier to support the use of any type as a fixed
> value for
> >>>>>> each case (not just tuples). For example, say we introduced as new
> protocol:
> >>>>>>
> >>>>>> protocol ExpressableByTuple {
> >>>>>> associatedtype TupleType // somehow force this to be a tuple or
> >>>>>> ExpressableByType type
> >>>>>> init(tupleLiteral:TupleType)
> >>>>>> }
> >>>>>>
> >>>>>> With a bit of magic all tuples could conform to this protocol with
> >>>>>> themselves as the literal type, allowing us to use them as enum raw
> values;
> >>>>>> likewise this could then be used to more easily enable any custom
> >>>>>> struct/class for storage in enum cases, as instead of supporting
> their
> >>>>>> constructors directly we can just support construction via a tuple
> literal.
> >>>>>>
> >>>>>>
> >>>>>> My other reason I don't favour option 1, while it looks a bit
> prettier, is
> >>>>>> that it's a bit confusing; enums have two types of stored
> properties, ones
> >>>>>> that can be changed (and inspected) which is what you get when you
> declare
> >>>>>> case small(Int, Int) for example, these are stored as part of the
> enum
> >>>>>> itself (so in that example it's 17-bytes on a 64-bit system).
> However
> >>>>>> rawValues are more like constants/static values, and don't increase
> the size
> >>>>>> of the type, and I just feel that this is the right way to do what
> you're
> >>>>>> proposing.
> >>>>>>
> >>>>>> _______________________________________________
> >>>>>> swift-evolution mailing list
> >>>>>> swift-evolution at swift.org
> >>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> >>>>>>
> >>>>>>
> >>>>> _______________________________________________
> >>>>> swift-evolution mailing list
> >>>>> swift-evolution at swift.org
> >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> >>>>
> >>> _______________________________________________
> >>> swift-evolution mailing list
> >>> swift-evolution at swift.org
> >>> https://lists.swift.org/mailman/listinfo/swift-evolution
> >>
> >
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161012/30654616/attachment.html>


More information about the swift-evolution mailing list