[swift-evolution] Working with enums by name

Leonardo Pessoa me at lmpessoa.com
Tue May 31 14:36:17 CDT 2016


Since we're talking a lot enums these days, I'd like to bring into
discussion a proposal that has been briefly mentioned in another
thread to enable working with enums using their names.

This is currently possible in the language but it's a bit burdensome.
You can just interpolate the value of the enum into a string to get
its name/representation as a string but you have to write case by case
the init methods for each enum to convert the string back to its
value. For example:

|   enum Planet : Int {
|      case Mercury = 1, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune
|
|      init?(caseName name : String) {
|          switch name {
|              case "Mercury":
|                  self = .Mercury
|              case "Venus":
|                  self = .Venus
|              case "Earth":
|                  self = .Earth
|              case "Mars":
|                  self = .Mars
|              case "Jupiter":
|                  self = .Jupiter
|              case "Saturn":
|                  self = .Saturn
|              case "Uranus":
|                  self = .Uranus
|              case "Neptune":
|                  self = .Neptune
|              default:
|                  return nil
|          }
|      }
|   }
|
|   let planet = Planet(caseName: "Earth")!
|   print("\(planet) = \(planet.rawValue)") // Earth = 3

My proposal here is to let the compiler create these initialisers
automatically, just like with rawValue.

The reasoning here is simple: Enums in their basics are values, like
Int values or Double values, but limited to a closed set and
referenced in code by a name. Although they *may* have raw value
equivalents not all do (they don't need to). Using the name of the
enum value instead of any value associated with it also benefits
persistence since these associated values can change overtime while
the name is less likely to change.

As an example of the importance of this proposal, I mention the
company I work for who chooses to store (DB) the names of enum values
where they are used in persisted data arguing it's easier to debug and
support, and several web services we work with send enumerated values
as the strings of their names which we have to convert back to the
enum value when we receive. This proposal would simplify writing such
parts of the apps.

In case you're thinking, enums with associated values can also have
their instances created this way because there seems to be a default
representation for them in string interpolation. It's possible to be
done manually but would require a lot more of code and effort to be
converted back:

|   enum Platform {
|      case OSX(version: String)
|      case iOS(version : Int)
|   }
|
|   let plat = Platform.iOS(version: 9)
|   print("\(plat)") // iOS(9)
|
|   let plat2 = Platform.OSX(version: "10.10.4")
|   print("\(plat2)")  // OSX("10.10.4")

Furthermore, I'm aware the output of the string interpolation may be
altered by adopting certain protocols so it should also be interesting
for this proposal to add a property like .caseName to all enums to
ensure the correct string representation that would be converted back
to the enum value.

I'd like to hear your opinions before writing a proposal.
Thanks.

L


More information about the swift-evolution mailing list