> Brent, for needing "both Int and Double values" there is a proposal to add 
> tuples instead of the current raw values or allowing assessor properties per 
> case, you should check those out. Perhaps this could also be used to 
> cryptoghaphically sign a raw value but I'm not sure.

I know; I was the one who suggested accessors.

> As for working with enum values by name a few examples have already been 
> posted in today but I've done a lot more research in the subject along the 
> day and found there is a correlation between enums and nominal level values 
> in statistics; we cannot test them for a particular order (this could also be 
> interesting for statistic apps but it's another case) and no math with them 
> is valid. So, e.g., the result of the following operation on the planets enum 
> is nonsense:
> 
> |   let planet = Planet(rawValue: Planet.Mars.rawValue - 
> Planet.Mercury.rawValue)
> 
> The result will be different if the enum values are zero based than if not. 
> Also any change in list order or the base index or add a new element to the 
> middle of the list will break your intended code if you're storing the raw 
> value in a database. And we know these changes happen.

All of this is true. And all of this is an argument that *you're using raw 
values wrong*.

Raw values are a serialization mechanism. You might be serializing merely 
within your process, or you might be writing out to disk, through IPC, or 
across the network, but in all cases you are serializing. You should not be 
doing arithmetic with a serialized representation (unless that arithmetic is a 
part of the serialization process, like an error-correcting code you're 
applying to it). You should not be sorting serialized representations. You 
should be either communicating the raw value or recreating the instance with 
it—nothing else.

In other words, all of these are arguments for putting the order of the Planet 
in a separate property rather than in the `rawValue`. This would free up the 
`rawValue` to be a `String` containing the case name. This is not an argument 
for having both an Int `rawValue` and a String `caseName`; this is an argument 
for having both a String `rawValue` and an Int property.

        enum Planet: String {
                accessor var order: Int
                
                case mercury { order = 0 }
                case venus { order = 1 }
                ...etc...
        }

(Want it to be automatic? One could imagine having a compiler substitution for 
"the index of this case" which could be used as the default value for an 
accessor:

        enum Planet: String {
                accessor var order: Int = #caseIndex
                case mercury, venus, ...
        }

Or let you choose a base:

        enum Planet: String {
                accessor var order: Int = #caseOrder(from: 1)
                case mercury, venus, ...
        }

Or the `ValuesEnumerable` proposal would give you a convenient, though slightly 
slow, way to do two-way lookup by order:

        enum Planet: String, ValuesEnumerable {
                var order: Int {
                        return Planet.allValues.index(of: self)!
                }
                init(order: Int) {
                        self = Planet.allValues[order]
                }
                case mercury, venus, …
        }

In short, there are several plausible mechanisms to automate assignment of 
these numbers, should you want to do that.)

> Actually, given this characteristic of nominal types (statistic), we should 
> vow to removing init(rawValue:) completely from the language.

That doesn't follow. The fact that changing something would break code doesn't 
mean that thing should be removed; it means you should be cautious about 
changing that thing. If you rename a case, its name changes; does that mean we 
shouldn't have case name lookups either? Changing any identifier could break 
something; maybe we should abolish all identifiers from Swift?

> The real value you're working with in enums is the enum case name not any 
> associated values. By working with the name you're safe should any associated 
> value change, should their order change, you'll only break your app if the 
> case is removed/renamed (with the raw value, you risk having the wrong 
> treatment being given should another enum case takes the value of a removed 
> one).

RawRepresentable is a serialization mechanism, so *of course* changing the raw 
value can break serialization. This is true whether you're using `Int` raw 
values or `String` raw values; it's just that `Int`s are a little easier to 
change.

If you create an enum with raw values, the raw values are more or less part of 
that enum's contract. You shouldn't expect things to continue to work properly 
if you change them, any more than you should expect them to continue to work 
properly if you delete a case. In fact, the library resilience document 
specifically calls out changing raw values as a "binary-compatible 
source-breaking change": 
<https://github.com/apple/swift/blob/master/docs/LibraryEvolution.rst#enums>

> I agree there are lots of important and more difficult things to review in 
> the language but I wouldn't be wasting my time here if I didn't think this 
> was equally important.

I don't see how it's particularly important to solve this bizarre corner case 
of needing both a non-String raw value *and* a way to look up cases by name, 
particularly since you *still* have not provided a decent example where the 
non-String rawValue ought to be a rawValue at all.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to