> RawRep is two things: a failable initialiser, and a getter.
> When the compiler synthesises them, it generates those
> exact same switch statements I proposed before. It’s quite
> simple, and there are potential issues to allowing arbitrary
> structs to use the same system. For one thing, they don’t all
> have a 1:1 equivalence relationship, so it’s possible for multiple
> enum cases to match the same raw struct. In that case, the order in
> which the compiler synthesises its checks is important, but it’s quite
> a hidden implementation detail that you wouldn’t be able to debug easily.
> It’s better to ask the user to implement the RawRep requirement
> themselves in those cases; it’s not a lot of work.

I'm aware of what is a basic idea behind RawRep. But it seems that I had a
wrong understanding of how rawValue's are managed. I was not aware of
the fact, that rawValue is created 'on demand' every time you use
.rawValue property on enum case. What it means, is that if you are
using a struct as a rawValue it is recreated from a string every
single time you are accessing rawValue. Not cool :)

Taking that into account I would consider changing the approach to
somethin more like
(http://swiftlang.ng.bluemix.net/#/repl/57febc248ef62b25bcea2a8a)
enum Format {

    struct FormatStruct {
        var width: Int = 0
        var height: Int = 0

        private init(width: Int, height: Int) {
            print("GENERATE")
            self.width = width
            self.height = height
        }

        internal static let SMALL = FormatStruct(width: 30, height: 30)

        internal static let MEDIUM = FormatStruct(width: 60, height: 60)

        internal static let LARGE = FormatStruct(width: 120, height: 120)

    }

    case SMALL
    case MEDIUM
    case LARGE

    var size: FormatStruct {
        switch self {
        case .SMALL:
            return Format.FormatStruct.SMALL
        case .MEDIUM:
            return Format.FormatStruct.MEDIUM
        case .LARGE:
            return Format.FormatStruct.LARGE
        }
    }
    var width: Int {
        return size.width
    }
    var height: Int {
        return size.height
    }
}

I have to admit I was not expecting that. I thought, enum case
rawValues are managed similar to statics and only referred to by enum
cases. That was also a reason why I was convinced what 'storing'
values in properties could be achieved as a variation of rawValue.

Taking all of that into account I could agree that this proposal is more a
syntax update than a new language feature. Storing additional
properties would mean
1. store values as a part of enum case = extending required memory
(like it is done in case of associated values)
2. force compiler to generate a rawValue struct implementing
RawRepresentable protocol

> What I meant by that is that you want convenience accessors for extra stuff 
> you want to put in the enum’s payload (where the associated values are).
> I don’t think those values belong in the enum’s payload at all.

I never wanted to put anything in enum payload.

> What you propose looks dangerously close to the syntax for associated values, 
> IMO. A cleaner version might look like (strawman syntax):

No. It does not look event similar to what you described.

--
| Mateusz Malczak
+-------------------------------



2016-10-12 21:20 GMT+02:00 Karl <razie...@gmail.com>:
>
>> On 12 Oct 2016, at 18:44, Mateusz Malczak <mate...@malczak.info> wrote:
>>
>> I got a bit confused, I think we are here talking about completely
>> different features. Lets take a look at example from Karl
>>
>>> 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.
>>
>> This is something we already have - and example of enum with
>> associated values attached to enum cases. It has nothing to do with
>> this proposal.
>
> Yes, I know what it shows. I’m saying that your proposed syntax looks 
> dangerously close to what we already have (IMO), but means something entirely 
> different.
>
>>
>> The proposal is about being able to add stored immutable properties to enum 
>> type
>> (not to enum cases as it is in case of associated values). Just like you can
>> store properties in structs.
>>
>
> If the properties are:
>  - immutable, and
>  - tied to specific enum cases
>
> then there is no need for them to be stored. You are asking to produce a 
> hard-coded value based on the value of the enum - basically to wrap a switch 
> statement.
> We don’t need to store copies of numbers that are already baked in to your 
> source code.
>
>>> I think he wants convenience accessors for the associated values; the
>>> problem is that in his example, he shouldn’t even be using associated values
>>> at all.
>>
>> No, you are wrong, as I wrote its not even about associated values nor
>> about accessors.
>>
>
> What I meant by that is that you want convenience accessors for extra stuff 
> you want to put in the enum’s payload (where the associated values are). I 
> don’t think those values belong in the enum’s payload at all.
>
>>> You can already use structs as raw types. You just have to implement the 
>>> RawRepresentable conformance yourself.
>>
>> I know. And this has been also already discussed. Please see a
>> previously discussed example here:
>> https://swiftlang.ng.bluemix.net/#/repl/57fbf08a4f9bcf25fdd41634
>>
>> And one more example with UIView stored in enum cases
>> http://swiftlang.ng.bluemix.net/#/repl/57fe67ad4bb9da26d5438387
>>
>> The only problem here is an amount of boilerplate code you need to
>> create and limitations caused by using ExpressibleBy(*)Literal.
>>
>
> RawRep is two things: a failable initialiser, and a getter.
> When the compiler synthesises them, it generates those exact same switch 
> statements I proposed before. It’s quite simple, and there are potential 
> issues to allowing arbitrary structs to use the same system. For one thing, 
> they don’t all have a 1:1 equivalence relationship, so it’s possible for 
> multiple enum cases to match the same raw struct. In that case, the order in 
> which the compiler synthesises its checks is important, but it’s quite a 
> hidden implementation detail that you wouldn’t be able to debug easily. It’s 
> better to ask the user to implement the RawRep requirement themselves in 
> those cases; it’s not a lot of work.
>
> Most of the time, when you’re talking about things more complex than a number 
> or string, you only care about going from enum -> value. It’s much rarer that 
> you want to take a complex struct and condense it down in to a single enum 
> case.
>
>>> 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.
>>
>> I agree when it comes to memory and performance, but at the same time
>> we do not have to focus on how it should be laid out in memory. This
>> is already solved. It is now possible to create enumeration type with
>> custom structs as a rawType (see examples above). Enumeration type with
>> stored properties could be handled in exactly the same way. Taking
>> this into account I don't see any danger in terms of memory or
>> performance hits.
>>
>> In my opinion it's also not a syntactic sugar.
>>
>> Lets get back to the previously discussed example
>>
>> We are discussing here a enumeration type defined as
>> 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)
>> }
>> where
>> var size: RectSize = .small
>> size.height == 30 // true
>> size.rawValue // Error:  RectSizes has no property `rawValue`.
>> size.height = 40 // Error:  `height` is immutable
>> print(size.height) // output: 30
>>
>>
>> There are at least two ways of this could be done.
>>
>> First solution would be to implement this as a new feature next to
>> already existing two (enum with associated values, enum with
>> rawValue). I don't have any detailed implementation in head.
>
> As I explained, "enum with rawValue” isn’t a feature. It’s a computed 
> property - either one you implement yourself, or synthesised by the compiler 
> for a couple of basic cases.
> What you want is a computed property, but you want to write the values near 
> the cases instead of in a switch statement because they’re ugly. The compiler 
> will have to use those labels and synthesise the switch statement for you, 
> like it does for RawRep.
>
> What you propose looks dangerously close to the syntax for associated values, 
> IMO. A cleaner version might look like (strawman syntax):
>
> enum RectSize {
>   @property(width, 30)
>   @property(height, 30)
>   case small
>
>   @property(width, 60)
>   @property(height, 60)
>   case medium
> }
>
> But that looks even uglier than having a switch statement. So then you think, 
> what about if you could move those declarations elsewhere? maybe group them 
> to avoid redundant typing?
>
> enum RectSize {
>    case small
>    case medium
>
>   @property(width: Int)
>       small = 30
>       medium = 60
>   @endproperty
>
>    ..etc
> }
>
> and presto! You have basically reinvented the switch statement in a computed 
> property.
>
>>
>> Second approach would be to use struct as a rawValue. This feature is
>> already available.
>>
>> struct UnderlyingRectSizeEnumStruct {
>>    var width: Int
>>    var height: Int
>>    init(width: width, height: height) {
>>        self.width = width
>>        self.height = height
>>    }
>> }
>>
>> enum RectSize: UnderlyingRectSizeEnumStruct
>> {
>>   case small(width: 30, height: 30)
>>   case medium(width: 60, height: 60)
>>   case large(width: 120, height: 120)
>> }
>>
>>
>> I hope this explains what was the initial idea behind this proposal.
>>
>> --
>> | Mateusz Malczak
>> +-------------------------------
>>
>> 2016-10-12 17:07 GMT+02:00 Karl <razie...@gmail.com>:
>>> 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.
>>>
>>> - Karl
>>>
>>>> On 12 Oct 2016, at 13:52, Rien <r...@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 <razie...@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@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 <r...@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@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
>>>>>>>> +-------------------------------
>>>>>>>> | mate...@malczak.info
>>>>>>>> | http://malczak.info
>>>>>>>>
>>>>>>>>
>>>>>>>> 2016-10-11 23:42 GMT+02:00 Braeden Profile <jhaezhy...@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@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
>>>>>>>>> +-------------------------------
>>>>>>>>> | mate...@malczak.info
>>>>>>>>> | http://malczak.info
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> 2016-10-10 23:42 GMT+02:00 Haravikk <swift-evolut...@haravikk.me>:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On 10 Oct 2016, at 20:34, Mateusz Malczak <mate...@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@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

Reply via email to