Extending Bool for Entertainment and New Control Structures in Swift
I'm playing around with the Swift extension and stumbled upon a strange error while trying to extend Bool:
typealias Task = ()->()
extension Bool{
func untilFalse(task: Task){
while !self {println(self); task()}
}
}
var i = 2
(i < 1).untilFalse{
println(i)
println("\(i) bottles of beer on the wall, \(i) bottles of beer.")
i--
println("Take one down and pass it around, \(i) bottles of beer on the wall.")
}
For some reason, the loop just goes on and on, even after the expression boolean
has become true
.
Any ideas on what might be going on?
source to share
The problem is that the expression i < 1
will be evaluated once, the result will be false
. It will not be constantly reviewed. To achieve this, you will have to replace it with a function or a closure.
If you really want to, you can rewrite your code like this:
typealias Task = ()->()
typealias BooleanExpression = () -> Bool
infix operator *** {}
func *** (b: BooleanExpression, t: Task) {
while !b() { t() }
}
var i = 2
let exp: BooleanExpression = { i < 1 }
exp *** {
println(i)
println("\(i) bottles of beer on the wall, \(i) bottles of beer.")
i--
println("Take one down and pass it around, \(i) bottles of beer on the wall.")
}
But that's pretty damn ugly!
source to share
In the same direction as Colin's expression, but building it with auto-closure, you can use:
typealias Task = ()->()
infix operator *** {}
func ***(expression:@autoclosure ()->Bool, task:Task) {
while !expression() {
task()
}
}
var i = 2
(i < 1) *** {
println(i)
println("\(i) bottles of beer on the wall, \(i) bottles of beer.")
i--
println("Take one down and pass it around, \(i) bottles of beer on the wall.")
}
This simplifies things a bit. Of course, the natural syntax would be to just use something like:
func untilFalse(expression:@autoclosure ()->Bool, block:()->()) {
while(!expression()) {
block()
}
}
var i = 2
untilFalse(i < 1) {
println("\(i) bottles of beer on the wall, \(i) bottles of beer.")
i--
println("Take one down and pass it around, \(i) bottles of beer on the wall.")
}
Which builds on the autoclosure and trailing block syntax to appear to add a new type of statement to the language
source to share