Check if variable is a block / function / callable in Swift -


is there simple , definite way in swift check whether callable block / function? in languages it's trivial thing, perhaps i'm looking @ wrong perspective in swift? consider 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 () -> ()) // true print(bar () -> ()) // true print(baz () -> ()) // false print(baz () -> (bool)) // true 

swift knows functions, though there no such data type. can check using solid signature, there might situation don't care signature* , want invoke it. example:

func call(callable: () -> ()) {     callable() }  call(foo) // foo call(bar) // bar call(baz) // error: cannot convert value of type '() -> (bool)' expected argument type '() -> ()' 

i can rewrite this, work void , bool return types, doing every type crazy, since don't care it, 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 signature sin. argument sake let's not care return type.

you can check string representation of .dynamictype of callable existence of substring ->. not super-elegant, works:

func isaclosure<t>(foo: t) -> bool {     return string(foo.dynamictype).containsstring("->") }  var : () -> () = { print("foobar") } var b : (double) -> (bool) = { $0 > 0 } var c : int = 1  isaclosure(a) // true isaclosure(b) // true isaclosure(c) // false 

of course, marcus rossel points out in comment above, still wouldn't know parameters of callable (but perhaps next step find out, given know it's callable).


addition regard ops questions below: technical discussion, , not recommended techniques.

you use same approach above check if function argument closure without arguments (() -> (...)) or 1 neither arguments nor return type (() -> ()), , on. using approach, can define generic function call argument sent function if of closure type. "in-function-call", you'll have make use of type conversion expected closure type, you've described in q above. it'll difficult circumvent "non-generic" approach w.r.t. calling closures. 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 : () -> () = { 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) 

Comments

Popular posts from this blog

authentication - Mongodb revoke acccess to connect test database -

r - Update two sets of radiobuttons reactively - shiny -

ios - Realm over CoreData should I use NSFetchedResultController or a Dictionary? -