Is there a simple and definite way in Swift to check whether something is a callable block / function? In some languages it's a trivial thing, but perhaps I'm looking at this from a wrong perspective in Swift? Consider the following.
func foo(){ print("foo") }
var bar: () -> () = { print("bar") }
var baz: () -> (Bool) = { print("baz"); return true }
print(foo) // (Function)
print(bar) // (Function)
print(baz) // (Function)
print(foo is () -> ()) // true
print(bar is () -> ()) // true
print(baz is () -> ()) // false
print(baz is () -> (Bool)) // true
Swift knows that they are all functions, though there is no such data type. I can check by using a solid signature, but there might be a situation where I don't care about the signature* and simply want to invoke it. For example:
func call(callable: () -> ()) {
callable()
}
call(foo) // foo
call(bar) // bar
call(baz) // error: cannot convert value of type '() -> (Bool)' to expected argument type '() -> ()'
I can rewrite it like this, which will work for Void and Bool return types, but doing this for every type is crazy, especially since I don't care about it, but compiler does…
func call(callable: Any) {
if let block: () -> () = callable as? () -> () {
block()
} else if let block: () -> (Bool) = callable as? () -> (Bool) {
block()
}
}
call(foo) // foo
call(bar) // bar
call(baz) // truely baz
* Agree, not caring about the signature is a sin. For the argument sake let's just not care about the return type.
You can check the String representation of .dynamicType of the callable for existence of substring ->. Not super-elegant, but it works:
func isAClosure<T>(foo: T) -> Bool {
return String(foo.dynamicType).containsString("->")
}
var a : () -> () = { print("Foobar") }
var b : (Double) -> (Bool) = { $0 > 0 }
var c : Int = 1
isAClosure(a) // true
isAClosure(b) // true
isAClosure(c) // false
Of course, as Marcus Rossel points out in the comment above, you still wouldn't know anything about the parameters of the callable (but perhaps that could be next step to find out, given that you know it's a callable).
Addition with regard to OPs questions below: just a technical discussion, and not recommended techniques.
You use the same approach as above to check if the function argument is a closure without arguments (() -> (...)) or one with neither arguments nor return type (() -> ()), and so on. Using this approach, you can define a generic function that call the argument sent to the function only if it is of a certain closure type. For this "in-function-call", you'll have to make use of type conversion to expected closure type, much as you've described in your Q above. It'll probably be difficult to circumvent this "non-generic" approach w.r.t. calling the closures. A few examples follow below.
/* Example functions */
func isAVoidParamClosure<T>(foo: T) -> Bool {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
return bar.count > 1 && (bar.first?.characters.count ?? 0) == 2
}
func callIfVoidVoidClosure<T>(foo: T) {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
if bar.count > 1 && !(bar.map{ $0 == "()" }.contains(false)) {
if let foo = foo as? () -> () {
foo()
}
}
}
func isASingleDoubleReturnTypeClosure<T>(foo: T) -> Bool {
let bar = String(foo.dynamicType).componentsSeparatedByString(" -> ")
return bar.count > 1 && bar[1] == "Double"
/* rhs of '&&' lazily evaluated: [1] ok */
}
func printTwoTimesResultOfVoidDoubleClosure<T>(foo: T) {
if isAVoidParamClosure(foo) && isASingleDoubleReturnTypeClosure(foo) {
if let foo = foo as? () -> Double {
let a: Double = 2*foo()
print(a)
}
}
}
Example calls:
/* Example calls */
let a : () -> () = { print("Foobar") }
let b : (Double) -> (Bool) = { $0 > 0 }
let c : () -> Double = { 21.0 }
let d : Int = 1
isAVoidParamClosure(a) // true
isAVoidParamClosure(b) // false
isAVoidParamClosure(c) // true
isAVoidParamClosure(d) // false
callIfVoidVoidClosure(a) // Prints "Foobar"
callIfVoidVoidClosure(b)
callIfVoidVoidClosure(c)
callIfVoidVoidClosure(d)
printTwoTimesResultOfVoidDoubleClosure(a)
printTwoTimesResultOfVoidDoubleClosure(b) // Prints "42.0"
printTwoTimesResultOfVoidDoubleClosure(c)
printTwoTimesResultOfVoidDoubleClosure(d)
Related
This compiles:
let badger = get_closure()
func get_closure() -> (Int) -> Void {
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
This doesn't with circular reference errors:
let badger = get_closure()
let get_closure = { () -> (Int) -> Void in
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
Why? I thought the func syntax is just sugar for the second more explicit syntax.
The fact that the first one works is a long-standing bug/quirk in the compiler, not an intended feature. It's based on undefined behavior that the compiler has trouble detecting. You can demonstrate that it's a quirk of top-level declarations by wrapping your working code in a function and see that it fails very similarly to your second example:
func f() {
let badger = get_closure()
func get_closure() -> (Int) -> Void { // ERROR: Closure captures 'badger' before it is declared
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
badger(1)
}
The key feature of top-level, global declarations like badger is that they're lazily evaluated, so the assignment actually happens after the declaration of the function. In your second example, both variables are lazy, so the order comes back in. But it's dangerous to rely on this fact, as discussed in the linked forum posts.
When exploring subtle Swift behavior, I always recommend building a commandline app and placing your test code inside of a function to eliminate the weirdness of both Playgrounds and top-level executable code. (Playgrounds isn't relevant in this case, but it comes up a lot.)
It's hard to understand where this approach should be used, but if you really want to, then try this:
let get_closure: (Int) -> Void = { x in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
let badger = get_closure
badger(1)
The order of initialization of dependent variables is usually important. If you assign a value after the closure, there will be no error:
let get_closure = { () -> (Int) -> Void in
return { (x: Int) -> Void in
print(x)
if x > 4 {
return
} else {
badger(x + 1)
}
}
}
let badger = get_closure()
badger(1)
Is Map function of Optional in Swift just used to transform?
If I want do something just Optional has some value, Can I Use map function? if not, why?
According to apples examples, we used map like this
let possibleNumber: Int? = Int("42")
possibleNumber.map { $0 * $0 }
Can I use it like this? : (If it's not proper, how to explain it)
func setImage(with data: Data?) {
data.flatMap { UIImage(data: $0) }
.map { imageView.image = $0 }
}
Furthermore map function should return a value, but why this function does not have any warning about not used of result ( such as result of call map{...} is unused ) ?
You certainly can do it, it's just not very conventional. When people see map, they have a pre-conceived expectation that it'll be doing a transformation. You're violating that expectation, but there's nothing technically "wrong" about it.
Personally, I prefer using this extension:
extension Optional {
/// An enum used to ensure that `ifNone` is never called before `ifSome`.
enum IfSomeResult {
case some
case none
func ifNone(_ closure: () throws -> Void) rethrows -> Void {
switch self {
case .some: return
case .none: try _ = closure()
}
}
}
#discardableResult
func ifSome(then closure: (Wrapped) throws -> Void) rethrows -> IfSomeResult {
if let wrapped = self {
try _ = closure(wrapped)
return IfSomeResult.some
}
else {
return IfSomeResult.none
}
}
func ifNone(then closure: () throws -> Void) rethrows -> Void {
if case nil = self { try _ = closure() }
}
}
And writing code like:
data.flatMap { UIImage(data: $0) }
.ifSome { imageView.image = $0 }
Why doesn't it warn about an unused value?
The closure is inferred to return Void (the empty tuple type, whose only value is the empty tuple, ()). The compiler never emits warnings about Void values being unused`. Here's an example:
Optional(123).map { _ in () }
Below, there are one protocol which has two closure variables and a functions. And there is also a class conforming to the protocol.
import Foundation
protocol TestProtocol: class {
var firstClosure: () -> () { get set }
var secondClosure: () -> () { get set }
func testFunction()
}
extension TestProtocol {
func testFunction() {
_ = firstClosure
_ = secondClosure
}
}
class A: TestProtocol {
var firstClosure: () -> ()
var secondClosure: () -> ()
var number = 0
init() {
print(number)
firstClosure = {
self.number = 1
}()
print(number)
secondClosure = {
self.number = 2
}()
print(number)
testFunction()
print(number)
}
}
let a = A()
My expected result is 0, 0, 0, 2. But, when I define closure variable, the closure variable execute immediately. What should I do?
The issue is that you aren't defining closures, you're defining Voids due to the fact that you execute the closures right after defining them by writing () after the closure. The type of firstClosure and secondClosure are both Void, which is a typealias for (). If you wanted to declare a closure that takes no input arguments and returns no value (or rather returns Void), you need to declare it as () -> ().
protocol TestProtocol: class {
var firstClosure: () -> () { get set }
var secondClosure: () -> () { get set }
func testFunction()
}
extension TestProtocol {
func testFunction() {
firstClosure()
secondClosure()
}
}
You should also modify your conforming class to directly set the closure's instead of setting them in the initializer and not to call a function with side effects (testFunction) in the initializer, but rather call it when you actually need it after initialisation. You need to declare your closures as lazy, since they access self.
class A: TestProtocol {
var number = 0
lazy var firstClosure: () -> Void = {
self.number = 1
}
lazy var secondClosure: () -> Void = {
self.number = 2
}
}
A().testFunction()
I try to manage my functions with a Manger. The problem is that the function code updates and is not saved in the moment when i add the function to my manager. I try to explain my problem with this example:
class QueueManager {
typealias FunctionType = () -> ()
private var functions = [(String, FunctionType)]()
func add(funcName: String, function: FunctionType) -> QueueManager {
functions.append(funcName, function)
return self
}
func runFirst() -> Bool {
guard functions.isEmpty == false else { return false }
functions.first!.1()
functions.removeFirst()
return true
}
}
Then i do this:
let queueManager = QueueManger()
var value = 1
queueManager.add("simpleFunction"){
print(value)
}
value = 2
queueManager.add("simpleFunction"){
print(value)
}
queueManager.runFist()
queueManager.runFist()
And the result is:
2 // Because value is 2 in both functions. But i added the function while value was 1??
2
But i want the result:
1
2
What am i doing wrong? Thanks in advance!
EDIT: Very easy playground example:
import UIKit
var str = "1"
func go() {
print(str)
}
var array:[()->()] = []
array.append(go)
str = "2"
array.append(go)
array[0]()
array[1]()
// Output:
// 2
// 2
EDIT 2:
I know that 2 2 is the right output for my code. But i want to keep the function in the state of its creation. Is this somehow possible?
EDIT 3:
Thanks for all of your help. But i think i`m failing to explain my problem enough to get suiting answers. I want to call a function with its parameters at a later time. I don't want to keep the reference to the parameter values. I just need to call the function with those parameter values.
In order to understand what happens here lets take a look step-by-step :
Assign 1 to value
Add the print instruction to QueueManager
Assign 2 to value
Add the print instruction to QueueManager
Run the functions using runFirst()
When you add the print(value) instruction you pass value as reference type. This creates a strong reference between variable functions and value. Hence when you actually execute those instructions, using runFirst() it then uses the value stored in value at that point of time.
Let's explore using this example:
var value = 5
queueManager.add(funcName: "simpleFunction"){
print(value)
}
queueManager.add(funcName: "simpleFunction"){
print(value)
}
queueManager.runFirst()
queueManager.runFirst()
value = 10
// output is 5 5
In this case we perform runFirst() first and then update the value. Hence the output is 5 5.
TL;DR - Pass By Reference causes function to print the current value of variable value.
EDIT : Bind the data to the function in QueueManager, this will make sure that the current value of data (during function definition) is associated with the function.
class QueueManager {
typealias FunctionType = (Int) -> ()
private var functions = [(String, FunctionType, Int)]()
func add(funcName: String, function: #escaping FunctionType, data: Int) -> QueueManager
{
functions.append((funcName, function, data))
return self
}
func runFirst() -> Bool
{
guard functions.isEmpty == false else { return false }
functions.first!.1(functions.first!.2)
functions.removeFirst()
return true
}
}
let queueManager = QueueManager()
// define you function within this closure
let functionClosure: (Int) -> () = { (data) in
print(data)
}
var value = 1
queueManager.add(funcName: "simpleFunction", function: functionClosure, data: value)
value = 2
queueManager.add(funcName: "simpleFunction", function: functionClosure, data: value)
queueManager.runFirst()
queueManager.runFirst()
OUTPUT :
1
2
Based on your code, obviously the result should be:
2
2
because you are calling queueManager.runFirst() tow times after editing value = 2
Also, if add function should includes functions.append((funcName, function)) then I assume that its function parameter should be #escaping as follows:
class QueueManager {
typealias FunctionType = () -> ()
private var functions = [(String, FunctionType)]()
func add(funcName: String, function: #escaping FunctionType) -> QueueManager {
functions.append((funcName, function))
return self
}
func runFirst() -> Bool {
guard functions.isEmpty == false else { return false }
functions.first!.1()
functions.removeFirst()
return true
}
}
Thus the output of:
let queueManager = QueueManager()
var value = 1
queueManager.add(funcName: "simpleFunction") {
print(value)
}
queueManager.runFirst()
value = 2
queueManager.add(funcName: "simpleFunction"){
print(value)
}
queueManager.runFirst()
should be:
1
2
because -simply- I called queueManager.runFirst() before calling value = 2
The same issue is applicable to your simple example:
var str = "1"
func go() {
print(str)
}
var array:[()->()] = []
array.append(go)
array[0]()
str = "2"
array.append(go)
array[1]()
calling array.append(go) won't leads to execute go(), you should call it by array[0](); Since you are trying to print the value of the same variable (str) it will always prints the latest value for it. If you want to save each value separately for each function, you should -somehow- declare more than one variable (value or str).
import UIKit
var str = "Hello, playground"
class QueueManager {
typealias FunctionType = () -> ()
private var functions = [(String, FunctionType)]()
func add(funcName: String, function: #escaping FunctionType) -> QueueManager {
functions.append((funcName, function))
return self
}
func runFirst() -> Bool {
guard functions.isEmpty == false else { return false }
print(functions)
functions.first!.1()
functions.removeFirst()
return true
}
}
var value = 1
let queueManager = QueueManager()
func simpleFunction(_ value: AnyObject){
print(value)
}
queueManager.add(funcName: "simpleFunction"){
simpleFunction(value as AnyObject)
}
queueManager.add(funcName: "simpleFunction"){
value = 2
simpleFunction(value as AnyObject)
}
queueManager.runFirst()
queueManager.runFirst()
You have to update your value after the first simpleFunction was added.
Playground Output:
[("simpleFunction", (Function)), ("simpleFunction", (Function))]
1
[("simpleFunction", (Function))]
2
This function takes a Void -> T function and returns a Void -> T function.
func future<T>(f: Void -> T) -> Void -> T {
let queue = dispatch_queue_create("com.test.lockQueue", nil)
var results: T?
dispatch_async(queue) {
results = f()
}
return {
dispatch_sync(queue) {}
return results!
}
}
If I use it like this:
let f = future<Int> {
NSThread.sleepForTimeInterval(2)
return 10
}
I get the error "Cannot explicitly specialize a generic function".
If I however set the explicit type to Void -> Int like so:
let f: Void -> Int = future {
NSThread.sleepForTimeInterval(2)
return 10
}
It works but it doesn't look that good.
Can I change the function so that the I can use it in the first example?
You can define the function as a local function and pass it.
func sleepAndReturn() -> Int {
NSThread.sleepForTimeInterval(2)
return 10
}
let f = future(sleepAndReturn)
Alternatively you could use the in syntax to specify the type.
let f = future({ () -> Int in
NSThread.sleepForTimeInterval(2)
return 10
})
Or shorter:
let f = future({ _ -> Int in
NSThread.sleepForTimeInterval(2)
return 10
})
I think it should just work like this:
let f = future {
NSThread.sleepForTimeInterval(2)
return 10
}
... or if that is too difficult for Swift to figure out, then you can specify the closure parameters like this:
let f = future { Void -> Int in
NSThread.sleepForTimeInterval(2)
return 10
}
You can wrap the function in a struct and use it like this:
struct Future<T> {
static func create(f: Void -> T) -> Void -> T {
let queue = dispatch_queue_create("com.test.lockQueue", nil)
var results: T?
dispatch_async(queue) {
results = f()
}
return {
dispatch_sync(queue) {}
return results!
}
}
}
let f = Future<Int>.create {
NSThread.sleepForTimeInterval(2)
return 20
}