bricker
(Bryan Ricker)
1
Motivation
Binding associated values from an enum case to a local variable is verbose and often repetitive. For example:
enum Fruit {
case apple(diameter: Double, color: String)
case orange(diameter: Double)
case grapefruit(diameter: Double)
case banana
var circumference: Double? {
// Repeated code to pull associated value; encourages copy-pasting
switch self {
case .apple(let diameter, _): return diameter * PI
case .orange(let diameter): return diameter * PI
case .grapefruit(let diameter): return diameter * PI
case .banana: return nil
}
}
var color: String {
switch self {
case .apple(_, let color): return color
case .orange: return "orange"
case .grapefruit: return "pink"
case .banana: return "yellow"
}
}
}
Proposal
Bind associated values to local variables $0, $1, ... $n, where n is the number of associated values for that case.
Conceptually similar to a few existing features:
Anonymous Closure Arguments
[1,2,3].map { $0 + 1 }
Implicit variable binding in catch block
do {
try someRiskyOperation()
} catch {
print(error)
}
Implicit variable binding for property setters and observers
class Person {
init(name: String) {
self.name = name
}
var name: String {
willSet { print("setting name: \(newValue)") }
didSet { print("set name: \(oldValue)") }
}
}
Example usage
enum Fruit {
case apple(diameter: Double, color: String)
case orange(diameter: Double)
case grapefruit(diameter: Double)
case banana
var circumference: Double? {
switch self {
case .apple: return $0 * PI
case .orange: return $0 * PI
case .grapefruit: return $0 * PI
case .banana: return nil
}
}
var color: String {
switch self {
case .apple: return $1
case .orange: return "orange"
case .grapefruit: return "pink"
case .banana: return "yellow"
}
}
}
2 Likes
Jumhyn
(Frederick Kellison-Linn)
2
This would at least require some sort of opt-in in source since otherwise it would be source breaking for switch statements in closures that already use the $n variable names to refer to closure parameters.
4 Likes
davdroman
(David Roman)
3
You can always bind multiple cases at once, as long as the types match:
enum Fruit {
case apple(diameter: Double, color: String)
case orange(diameter: Double)
case grapefruit(diameter: Double)
case banana
var circumference: Double? {
switch self {
case .apple(let diameter, _),
.orange(let diameter),
.grapefruit(let diameter):
return diameter * PI
case .banana:
return nil
}
}
var color: String {
switch self {
case .apple(_, let color): return color
case .orange: return "orange"
case .grapefruit: return "pink"
case .banana: return "yellow"
}
}
}
Regardless, it'd be a -1 for me because $0 leaves no information left about the type/content of the associated values. This to me is a classic example of going against the principle of clarity over brevity.
3 Likes
t8n
4
+1
Maybe not using $0, $1, etc, but automatic binding to some other variable?
tera
5
There might be something here, so +1 from me.
As an alternative (or the two ways can coexist):
switch self {
case let v = .apple:
return v.0 * pi // positional argument, or
return v.diameter * pi // named argument (if there's a name)
.....
}
Edit: added the name argument use-case above for cases with named associated values.