[swift-evolution] [proposal draft] new syntax to access a given case's payload

Jérôme Duquennoy jerome+swift at duquennoy.fr
Mon Sep 26 10:51:03 CDT 2016


Summary
The aim of this proposal is to offer a new syntax to ease some uses of enums with payload.

Situation to improve:
Enums makes it possible to have explicate typing where it was not possible before. A classic example of that is filling a dictionary with data coming from a file or a stream (json, plist, …) : the types of possible values is finite : arrays, dicts, int, double, bool or string for json for exemple.
An enum can represent this finite range of possible types, its make the code and the API more self-documented.
Then, you have two possibilities to deal with this enum:
- using switch statements
- using the if case syntax introduced by swift 2

The drawback is that those two solutions can lead to writing code with high visual complexity, even though the logic behind is pretty simple.

Consider this example of a data dictionary, that a web service could have returned:
- book
  - title: 
  - author:
    - name: Apple
    - age: 40

We can decode this in a variable of type [String:Value], where Value is:

enum Value {
  case integer(value: Int)
  case string(value: String)
  case dict(value: [String:Value])
  case null
}

Here is a snippet of code to access the age of the author:

if case .dict(let book) = data {
  if case .dict(let author) = book["author"] ?? .null {
    if case .integer(let age) = author["age"] ?? .null {
      // now we have the age
    }
  }
}

The multiple indentation levels can rapidly make this code unattractive to read, and we need to add a null case to the enum to deal with optional values.

Proposed solution:
I suggest to add a new syntax, using the case keyword to ease access to the payload of such enums :

let payloadContent = case? .enumCase(variable)

The payloadContent variable will be an optional, that can be either nil, or contain the payload of enumCase.
If the payload contains multiple variables, payloadContent will be a tupple.
This syntax can accommodate an optional variable as an input. If the value of variable is nil, then payloadContent will be nil.
Only enum cases with a payload can be used with this syntax (it would make no sens for cases without a payload).

With that syntax, the null case of the enum can be removed, and the code to access the age becomes:

let book = case? .dict(inputData)
let author = case? .dict(book?["author"])
let age = case? .integer(author?["age"])

Advantages:
- It leverages the well established notion of optional, and similar logic already exists in the language (for the as? operator notably).
- It does not add a new keyword
- It promotes the use of enum to enforce explicit typing, which leads to more self-documenting code
- It reduces the complexity of the code in situations such as the one of the exemple

Drawbacks:
- It adds a third use of the case keyword. 
- In the proposed syntax, the variable between parenthesis is not the payload, but the variable to decode. This might be disturbing, as it differs from the other syntax of enum values.
- If the payload is an optional, it is not possible to differentiate a non-matching case and a matching case a nil payload.

Alternatives:
- Another syntax without parenthesis could be used to avoid the second drawback:
let payload = case? .enumCase variable

Impact on existing code:
None, this is adding a new syntax


This proposal would have no impact on the ABI, so it probably does not fit the stage 1 of swift 4’s roadmap. But I would be glad to have your feedback, so that I can have a proposal ready once we enter stage 2.
So what your thoughts on that proposal ?

Thanks

Jerome

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160926/ff7d9bf2/attachment.html>


More information about the swift-evolution mailing list