Ding dong – the wicked switch
is gone!?
Here's my experiment with an if
statement that can also
behave like a switch
.
Put these things at the top level:
var refStr: String?
infix operator •
prefix operator -->
extension Any? {
static func •(obj: Any?, refObj: Any?) -> Bool {
if let refObj {
refStr = String(describing: refObj)
} else {
refStr = nil
}
if let obj {
return refStr == String(describing: obj)
} else {
return refStr == nil
}
}
static prefix func -->(obj: Any?) -> Bool {
if let obj {
return refStr == String(describing: obj)
} else {
return refStr == nil
}
}
}
Compare the new super if
with a regular switch
:
let someInt: Int = 3
if 1 • someInt { print("1")
} else if -->2 { print("2")
} else if -->3 { print("3")
}
switch someInt {
case 1: print("1")
case 2: print("2")
case 3: print("3")
default: break
}
Let's define some more variables to "switch":
enum Go { case up, down }
let someChar: Character = "c"
let someStr: String = "goose"
let someGo: Go = Go.up
let someOptGo: Go? = nil
if 1 • someInt { print("1")
} else if -->2 { print("2")
} else if "a" • someChar { print("a")
} else if -->"b" { print("b")
} else if "duck" • someStr { print("duck")
} else if -->"swan" { print("swan")
} else if Go.down • someGo { print("down")
} else if "up" • someOptGo { print("up")
} else if -->nil { print("nil")
} else if someChar == "c" { print("true")
} else { print("pass")
}
Benefits:
-
not having to choose between
switch
andif
-
consistently uses curly braces (unlike switches, that
behave more like Python) -
no mandatory defaults (checking exhaustiveness becomes
the responsibility of the programmer) -
do switch-like comparisons without the need to repeat a
possibly very long variable name -
freely mix conditions with switch-like comparisons
-
switch more than one variable in the same
if
statement
Things to consider:
How does it affect performance?
Will String(describing: ...)
, or alternatively \(...)
,
operate the same way in the future?
Disclaimer: The above strategy should not be used in any
critical application where safety is a concern, since it
relies on String(describing: ...)
It would be possible to avoid using String(describing: ...)
by making individual operators for a lot of types, but that
doesn't seem very practical.
The method introduced so far is not really a pitch, since
it can be done already. The actual pitch would be to make
it possible to write .up
instead of Go.up
, and to be able
to deal with intervals. Then, of course, the whole thing
should not have to rely on String(describing: ...)
If it would be desirable, a double dot could be used when
the super if
must be exhaustive:
if .up •• someGo {
print("up")
} else if -->.down {
print("down")
}
Okay, but how should the following example be tackled?
let instanceOfSomeSubClass: SomeSubClass = SomeSubClass()
let instanceOfSomeSuperClass: SomeSuperClass = instanceOfSomeSubClass
switch instanceOfSomeSuperClass {
case let var1 as SomeSubClass: print("var1")
case let var2 as OtherSubClass: print("var2")
default: break
}
Well, it's always possible to use a common trick to avoid
having to repeat a verbose variable name:
let ref = instanceOfSomeSuperClass
if let var1 = ref as? SomeSubClass { print("var1")
} else if let var2 = ref as? OtherSubClass { print("var2")
}