Removing a closure from an array but not using it causes compiler error "Expression resolves to an unused function". Is there a good way to avoid this, other than assigning the function to a throwaway variable?
typealias StringFunction = () -> String
var list = [StringFunction]()
list.append({ "Hello World!" })
let hi = list[0]() // "Hello World!"
list.removeAtIndex(0) // Expression resolves to an unused function
let _ = list.removeAtIndex(0) // Works
Assigning the result of the expression to a throwaway variable is the correct way to do that. In fact, this is the idiomatic way to treat unused results in Swift.
Hence (as noted in the comments of another answer) the correct solution the is:
typealias StringFunction = () -> String
var list = [StringFunction]()
list.append({ "Hello World!" })
let hi = list[0]()
_ = list.remove(at: 0) // Note there's no need for `let`
Doing so not only makes your code clearer about your intent (i.e. it indicates that you definitely don't need the result of the method), but also helps the compiler perform all sorts of useful optimizations.
This compiled for me:
typealias StringFunction = () -> String
var list = [StringFunction]()
list.append({ "Hello World!" })
let hi = list[0]() // "Hello World!"
list.removeAtIndex(0)()
Although this does call the function. (thanks Martin R)
Related
Why do we get strong reference circle in the second example, why we did not in the first example?
class Test1 {
var name: String = "Ted"
lazy var greeting = { return "Hello \(self.name)" }()
deinit{print("goodby1")} // No retain cycle here ..
}
var v1:Test1? = Test1()
v1?.greeting
v1 = nil //prints goodby1, dealocation done
class Test {
var name: String = "Mery"
lazy var greeting = {return "Hello \(self.name)"}
deinit{print("goodby")} //retain cycle here
}
var v: Test? = Test()
v!.greeting
v = nil
In the first example, the closure is executed one time, it returns a String, and that String is assigned greeting. There is no closure; nothing is captured. This is just an anonymous function. If you like, you can get rid of the self., just like in a named function. The key point is that the type of greeting is String.
In the second example, greeting is a closure value, which captures self. Since self holds greeting and greeting holds self, there's a loop. The key point is that the type of greeting is () -> String. This is almost certainly a mistake, since this is not how lazy is intended to be used.
(lazy is a pretty weird feature in Swift, and was probably a bad idea to include in the langauge. I try to avoid it as much as possible. There are several subtle ways to use it incorrectly, so it's not surprising that it's bitten you.)
Global functions are closures that have name and do not capture any values.
In swift a function is a spatial form of closure. The different is the function has a name and if it is an global function it cannot capture constants and variables from the surrounding context.
However, I found that the global function can also capture the constants and variables from the surrounding context also (please see the sample code below)
let referenceInt = 10
func addOne () -> Int {
return referenceInt + 1 //captured the constant referenceInt
}
let fooA = addOne
let fooB = addOne
let fooC = addOne
print(fooA()) //prints 11
print(fooB()) //prints 11
print(fooC()) //prints 11, (func addOne captured referenceInt ?)
print(referenceInt) //prints 10
Problems:
I believe I didn't fully understand the following concepts:
Simply define a function in playground (like addOne() -> Int here) may not means it is a global function
Having the wrong understanding of the "Capture" for this cases, this is not a capture at all, (but why?)
Helps I'm looking for:
I would be very appreciate you could point out which part I understand wrongly and would be even great that you can give me some explanation.
Thanks
PS:
This question might be a duplication of this one, however, I still post it since there is no clean answer on it yet and my question pushed the question a bit further. However, if you still want to close it, I respect that and I willing to learn from you.
First, I would question your premise. A closure is a closure. All functions in Swift are closures, and they all capture in just the same way.
Second, I don't see what your code has to do with capturing or closures. You are not doing anything in your code that tests whether anything is being captured. The assignment of the type let fooA = addOne doesn't do anything interesting, and the code inside addOne doesn't do anything interesting either. You are merely adding two values at the time the code runs. Certainly the code inside addOne is permitted to refer to the global variable referenceInt, but that is merely because it is in scope. You aren't doing anything here that elicits the special powers of a closure.
Here's a modification of your code that does show capturing in action:
struct Test {
var referenceInt = 10
func addOne () -> Int {
return referenceInt + 1 // capture
}
mutating func test() {
let fooA = self.addOne
let fooB = self.addOne
let fooC = self.addOne
referenceInt = 100 // :)
print(fooA()) //prints 11
print(fooB()) //prints 11
print(fooC()) //prints 11
print(referenceInt) //prints 100
}
}
var t = Test()
t.test()
We change referenceInt before calling fooA and so on. Calling fooA still gives 11, because the value of self.referenceInt was captured before we changed referenceInt.
I'm working with a C API from Swift and for one of the methods that I need to call I need to give a
UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
More Info:
Swift Interface:
public func presage_predict(prsg: presage_t, _ result: UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>) -> presage_error_code_t
Original C:
presage_error_code_t presage_predict(presage_t prsg, char*** result);
Generally, if a function takes a UnsafePointer<T> parameter
then you can pass a variable of type T as in "inout" parameter with &. In your case, T is
UnsafeMutablePointer<UnsafeMutablePointer<Int8>>
which is the Swift mapping of char **. So you can call the C function
as
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK { ... }
From the documentation and sample code of the Presage library I
understand that this allocates an array of strings and assigns the
address of this array to the variable pointed to by prediction.
To avoid a memory leak, these strings have to be released eventually
with
presage_free_string_array(prediction)
To demonstrate that this actually works, I have taken the first
part of the demo code at presage_c_demo.c and translated it
to Swift:
// Duplicate the C strings to avoid premature deallocation:
let past = strdup("did you not sa")
let future = strdup("")
func get_past_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(past)
}
func get_future_stream(arg: UnsafeMutablePointer<Void>) -> UnsafePointer<Int8> {
return UnsafePointer(future)
}
var prsg = presage_t()
presage_new(get_past_stream, nil, get_future_stream, nil, &prsg)
var prediction : UnsafeMutablePointer<UnsafeMutablePointer<Int8>> = nil
if presage_predict(prsg, &prediction) == PRESAGE_OK {
for var i = 0; prediction[i] != nil; i++ {
// Convert C string to Swift `String`:
let pred = String.fromCString(prediction[i])!
print ("prediction[\(i)]: \(pred)")
}
presage_free_string_array(prediction)
}
free(past)
free(future)
This actually worked and produced the output
prediction[0]: say
prediction[1]: said
prediction[2]: savages
prediction[3]: saw
prediction[4]: sat
prediction[5]: same
There may be a better way but this runs in playground and defines a value r with the type you want:
func ptrFromAddress<T>(p:UnsafeMutablePointer<T>) -> UnsafeMutablePointer<T>
{
return p
}
var myInt:Int8 = 0
var p = ptrFromAddress(&myInt)
var q = ptrFromAddress(&p)
var r = ptrFromAddress(&q)
What's the point of defining ptrFromAddress, which seems like it does nothing? My thinking is that the section of the Swift interop book which discusses mutable pointers shows many ways to initialize them by passing some expression as an argument (like &x), but does not seem to show corresponding ways where you simply call UnsafeMutablePointer's initializer. So let's define a no-op function just to use those special initialization methods based on argument-passing
Update:
While I believe the method above is correct, it was pointed out by #alisoftware in another forum that this seems to be a safer and more idiomatic way to do the same thing:
var myInt: Int8 = 0
withUnsafeMutablePointer(&myInt) { (var p) in
withUnsafeMutablePointer(&p) { (var pp) in
withUnsafeMutablePointer(&pp) { (var ppp) in
// Do stuff with ppp which is a UnsafeMutablePointer<UnsafeMutablePointer<UnsafeMutablePointer<Int8>>>
}
}
}
It's more idiomatic because you're using the function withUnsafeMutablePointer which is supplied by the Swift standard library, rather than defining your own helper. It's safer because you are guaranteed that the UnsafeMutablePointer is only alive during the extent of the call to the closure (so long as the closure itself does not store the pointer).
#IBAction func operate(sender: UIButton) {
if let operation = sender.currentTitle {
if let result = brain.performOperation(operation) {
displayValue = result
}
else {
displayValue = 0.0
}
}
}
I am new to coding so pardon my coding format and other inconsistencies. I have been trying out the iOS 8 intro to swift programming taught by Stanford university and I have ran into a problem with the modified calculator.
I get three errors. The first one is a swift compiler warning - at
if let result = brain.performOperation(operation)
It says
constant 'result' inferred to have type () which may be unexpected.
It gives me the suggestion to do this ----
if let result: () = brain.performOperation(operation)
The other two errors are
Bound value in a conditional binding must be of Optional type at if let result line
Cannot assign a value of type () to a value of Double at "displayValue = result"
Here is the github link if anyone needs more information on the code.
Thanks in advance.
Guessing from the errors, I expect that performOperation() is supposed to return Double? (optional double) while if fact it returns nothing.
I.e. it's signature is probably:
func performOperation(operation: String) {
// ...
}
.. while in fact it should be:
func performOperation(operation: String) -> Double? {
// ...
}
Reason why I think so is that this line: if let result = brain.performOperation(operation) is call "unwrapping the optional" and it expects that the assigned value is an optional type. Later you assign the value that you unwrap to the variable that seems to be of Double type.
By the way, the shorter (and more readable) way to write the same is:
displayValue = brain.performOperation(operation) ?? 0.0
It looks like brain.performOperation() does not return a result at all,
so there is no optional value, too.
I would like to learn and use more functional programming in Swift. So, I've been trying various things in playground. I don't understand Reduce, though. The basic textbook examples work, but I can't get my head around this problem.
I have an array of strings called "toDoItems". I would like to get the longest string in this array. What is the best practice for handling the initial nil value in such cases? I think this probably happens often. I thought of writing a custom function and use it.
func optionalMax(maxSofar: Int?, newElement: Int) -> Int {
if let definiteMaxSofar = maxSofar {
return max(definiteMaxSofar, newElement)
}
return newElement
}
// Just testing - nums is an array of Ints. Works.
var maxValueOfInts = nums.reduce(0) { optionalMax($0, $1) }
// ERROR: cannot invoke 'reduce' with an argument list of type ‘(nil, (_,_)->_)'
var longestOfStrings = toDoItems.reduce(nil) { optionalMax(count($0), count($1)) }
It might just be that Swift does not automatically infer the type of your initial value. Try making it clear by explicitly declaring it:
var longestOfStrings = toDoItems.reduce(nil as Int?) { optionalMax($0, count($1)) }
By the way notice that I do not count on $0 (your accumulator) since it is not a String but an optional Int Int?
Generally to avoid confusion reading the code later, I explicitly label the accumulator as a and the element coming in from the serie as x:
var longestOfStrings = toDoItems.reduce(nil as Int?) { a, x in optionalMax(a, count(x)) }
This way should be clearer than $0 and $1 in code when the accumulator or the single element are used.
Hope this helps
Initialise it with an empty string "" rather than nil. Or you could even initialise it with the first element of the array, but an empty string seems better.
Second go at this after writing some wrong code, this will return the longest string if you are happy with an empty string being returned for an empty array:
toDoItems.reduce("") { count($0) > count($1) ? $0 : $1 }
Or if you want nil, use
toDoItems.reduce(nil as String?) { count($0!) > count($1) ? $0 : $1 }
The problem is that the compiler cannot infer the types you are using for your seed and accumulator closure if you seed with nil, and you also need to get the optional type correct when using the optional string as $0.