Guard condition provokes compiler error that talks about closure
The problem, as explained by Martin in this Q&A, is that the ||
operator is implemented with an @autoclosure
second parameter, in order to allow for short-circuit evaluation (the right hand expression need only be evaluated if the left hand expression evaluates to false
).
Therefore in the expression
b == nil || self.a > 0
self.a > 0
is implicitly wrapped in a () -> Bool
closure. This is problematic, because it requires the capture of self
, so that a
can be accessed upon applying the closure.
However, in an initialiser, Swift tightly restricts what you can do with self
before it has been fully initialised. One of these restrictions is the inability to be captured by a closure – which is why you get a compiler error.
Although really, there's nothing wrong with the closure { self.a > 0 }
capturing self
before it's fully initialised, because all the closure is doing is accessing a
on it, which has already been initialised. Therefore, this is really just an edge case (for which there's an open bug report), which I hope will be smoothed out in a future version of the language.
Until then, one solution as shown by Martin in this Q&A, is to use a temporary local variable to create a copy of the value of self.a
, avoiding the capturing of self
in the closure:
class Foo {
var a: Int
var b: Int
init(a: Int, b: String?) throws {
// some computation meaning that a != self.a
self.a = a * 42
// temporary local variable to be captured by the @autoclosure.
let _a = self.a
guard b == nil || _a > 0 else {
throw "Too little a!"
}
self.b = self.a
}
}
extension String: Error {}
Obviously, this assumes that self.a != a
, otherwise you can just refer to a
instead of self.a
in the guard
condition.
What is the type of the logical operators?
If you "cmd-click" on the word "Swift" in the statement
import Swift
in Xcode and search for ||
then you'll find that it is declared as
func ||<T : BooleanType>(lhs: T, rhs: @autoclosure () -> Bool) -> Bool
The reason is the "short-circuiting" behaviour of the ||
operator: If the first
operand is true, then the second operand must not be evaluated at all.
So you have to declare the parameter as
combine: (Bool, @autoclosure () -> Bool) -> Bool
Example:
func combineWith(a : Bool, b : Bool, combine: (Bool, @autoclosure () -> Bool) -> Bool) -> Bool {
return combine(a, b)
}
let result = combineWith(false, true, ||)
println(result)
Note: I tested this with Xcode 6.1.1. The syntax for autoclosure
parameters changed in Swift 1.2 (Xcode 6.3) and I haven't been able yet
to translate the above code for Swift 1.2 (see also Rob's comments
below).
The only thing that I can offer at the moment are extremely ugly
workarounds. You could wrap ||
into a closure that does not have
autoclosure parameters:
func combineWith(a : Bool, b : Bool, combine: (Bool, () -> Bool) -> Bool) -> Bool {
return combine(a, { b })
}
let result = combineWith(false, true, { $0 || $1() } )
Or you go without the short-circuiting behaviour:
func combineWith(a : Bool, b : Bool, combine: (Bool, Bool) -> Bool) -> Bool {
return combine(a, b)
}
let result = combineWith(false, true, { $0 || $1 } )
Defining logical operator implies in lua
OOP-style calls
This gets rather hacky if it must truly be infix. What about simply using metatables for OOP-ish object:method(params)
syntax?
Assuming implies
is defined as
local function _implies(a, b)
if a ~= 0 then return b end
return 1
end
this would be implemented as
debug.setmetatable(0, {__index = {
implies = _implies
}})
and used as
i:implies(j)
if you want you a simpler dot syntax instead, consider using currying:
debug.setmetatable(0, {__index = {
implies = function(a) return function(b) return _implies(a, b) end end
}})
used as
i.implies(j)
A more "infix-ish" notation might be achieved by using the __call
metamethod, and passing a function name:
debug.setmetatable(0, {__index = {
implies = function(a) return function(b) return _implies(a, b) end end
}, __call = function(self, index) return self[index] end})
(i)("implies")(j)
If implies = "implies"
, this can even be shortened to (i)(implies)(j)
.
Hacky, "truly" infix notation
If infix notation is of utmost importance, yet you can't use the available metamethods as they are limited and rather unreadable, you can use even more currying and workarounds to use other metamethods to create operators that seemingly turn your function (at least syntactically) into an infix operator using a "proxy" metatable instead of the function. You can use whatever operators you like; just make sure they suit your needs in terms of associativity and precedency:
local implies_right_hand_mt = {
__mul = function(self, b)
return _implies(self.a, b)
end
}
local implies_left_hand = setmetatable({}, {
__mul = function(a)
return setmetatable({a = a}, implies_right_hand_mt)
end
})
implies = implies_left_hand
The syntax would then be i *implies* j
or "i *implies* j"
in your example (using the multiplication operator). You could however use all other operators (except the comparison operators) as well, including other arithmetic operators, as implies
is not a number but rather a table and may thus override number metamethods.
Side note
Consider using booleans instead of numbers. You'd get two advantages:
- Most metamethods aren't used by booleans (especially all arithmetic & bitwise metamethods);
- The logic operators
not
,and
andor
work; you don't have to use bitwise operators (although those work fine as well).
Explanation of zip, reduce and combine in Swift
zip(a, b)
produces a sequence of tuples pairing the values from a
and b
[(5, 3), (6, 6), (7, 10)]
That sequence is passed to reduce
one tuple at a time. reduce
takes two parameters. The first is the initial value for the runningTotal
, and the second is a closure named combine
which operates on each of the items in the sequence one call at a time.
In this case, the code is counting up the number of scores for Alice and Bob where their score is higher.
The use of default values $0
, $1.0
, and $1.1
makes the code a bit hard to interpret, but here is an equivalent version:
let pointsAlice = zip(a, b).reduce(0, combine: { (runningTotal, scores) in
return runningTotal + (scores.0 > scores.1 ? 1 : 0) } )
For each value in the sequence (such as (5, 3)
), that value gets passed to the combine
closure as scores
, and the runningTotal
gets the value from the previous iteration of reduce
. scores.0
refers to the first value in the tuple, and scores.1
refers to the second value in the tuple. The initial runningTotal
is the 0
that is passed to reduce
.
The combine
closure is returning the runningTotal
plus 1
if the first score is higher, or plus 0
otherwise. That value is then passed into the next call of combine
as the new runningTotal
value along with the next scores
tuple.
The final result is a count of scores where the first score is higher.
Swift: Combine condition and if-let with logical or
The equivalent to your code example would be:
if text == "" || Int(text) ?? 2 < 2 {
print("valid")
// do your previous "something
} else {
print("invalid")
}
which yields
"" -> valid
"1" -> valid
"2" -> invalid
"abc" -> invalid
Using Reduce to sum (Swift)
In a short way:
let reduced = array.reduce(0) { $1.isAvailable ? $0 + $1.bars.count : $0 }
Now, let's explicit it:
The logic is quite simple:
- We set the initial value to 0
- In the closure, we have two parameters, the first one is the current value (at start it's the initial value), which we'll increment at each iteration, and the second one is the element of the array. We return then the new value (partial) that we incremented or not according to your condition (here is
isAvailable
)
Explicitly:
let reduced2 = array.reduce(0) { partial, current in
if current.isAvailable {
return partial + current.bars.count
} else {
return partial
}
}
With a ternary if:
let reduced3 = array.reduce(0) { partial, current in
return current.isAvailable ? partial + current.bars.count : partial
}
Getting rid of the return
, see Functions With an Implicit Return
in Functions of Swift or Implicit Returns from Single-Expression Closures
of Closures of Swift.
let reduced4 = array.reduce(0) { partial, current in
current.isAvailable ? partial + current.bars.count : partial
}
With Shorthand Argument Names
on Closures of Swift.
let reduced5 = array.reduce(0) { $1.isAvailable ? $0 + $1.bars.count : $0 }
What aren't these two ways of expressing map function equivalent?
Looks like the Int.init
overload that accepts a Substring
has the following signature:
public init?<S>(_ text: S, radix: Int = 10) where S : StringProtocol
So, Int($0)
works because it uses the default radix
, but there isn't an Int.init(_:)
that accepts a Substring
- there's only Int.init(_:radix:)
that does - and so it fails.
But if there was one:
extension Int {
public init?<S>(_ text: S) where S : StringProtocol {
self.init(text, radix: 10)
}
}
then this would work:
let result1 = arr.compactMap(Int.init)
Related Topics
Where to Place a .Txt File and Read from It in a iOS Project
Wait for Swift Animation to Complete Before Executing Code
Swift: Equivalent Objective-C Runtime Class
Titletextattributes Uiappearance Font in iOS 7
Clipstobounds Causes Uiimage to Not Display in iOS10 & Xcode 8
Calayer - Cabasicanimation Not Scaling Around Center/Anchorpoint
Opens Apple Maps App from iOS App with Directions
Uicollectionview Multiple Sections and Headers
Swrevealviewcontroller Close Rear View When Tapping Front View
How to Access iOS Private APIs in Swift
Override Uiappearance Property for Mfmailcomposeviewcontroller
iOS 8+ Framework with Nested Embedded Framework
Embedding a Framework Within a Framework (iOS 8+)
Uicollectionview - iOS 10 - Crash on iPhone 6 Plus Simulator But Works on Real Device