I've a variable which is a function type. Now, in an other function I want to set a parameter as a function type. Instead of mentioning its (the parameter function's) parameter type and return type, I simple want to set the variable as a parameter type. why doesn't this work?
In playgrounds I get an error saying 'cannot find the function in scope'.
Basically what I'm saying is to use the new variable as a type for the parameter instead of the original functions definition (parameter and return type).
Change "{function}" to "{}" it see what I mean β it'd still print that. You are not calling "function" when write it without "()". The proper type signature for a function taking no parameters and returning nothing is
() -> Void
Note that you can't omit the "-> Void" part here even if you could do it when declaring a function:
func foo() -> Void
func foo() // same
By having a default parameter the way you wrote it:
func proc(function: () = f2())
you are saying that your parameter is of type "()" (aka Void) and that it's default value is a callout to a function "f2()" β that's that callout that leads to printing the output string. The way you wrote it you can't do anything useful with the passed parameter, it's a value of type Void β no way to call it, etc.
I'm not sure I fully understand you. Can you elaborate the last part. I actually tried it in Playgrounds and it worked. I copied the code and the output from there.
Are you saying I should write ()->void and not just () to be sure I'm telling the compiler that the parameter function is a function type and not a void type?
Also, while experimenting more with it, I tried this and it works...
func f1(toPrint string: String) { print(string) }
var f2 = f1
func proc(function: (String) -> () = f1(toPrint:)) {
function("function as default parameter")
}
proc()
This is better. Note that you are writing return type of the function parameter (the "-> ()") part. It's same as "-> Void" and you could use both forms interchangeably. Also note that compiler would permit:
func proc(function: (String) -> () = f1)
in this case as there is no ambiguity which f1 to use.
This is the wrong way that accidentally leads you to the wanted result. Remove "function" from the body - the behaviour will be the same. Or add a few more "function; function; function" in the body - you'll still have just one "hello" in the output. You are not using "function" in the body sensibly. Let me write the equivalent of your fragment with a slight modified function that returns Int (hopefully would be easier to see):
func f1() -> Int { print("hello"); return 42 }
var f2 = f1
func proc(function: Int = f2()) { function }
proc() // outputs one "hello"
func proc(function: Int = f2()) { 42 }
proc() // still outputs one "hello"
func proc(function: Int = f2()) { /* nothing in the body */ }
proc() // still outputs one "hello"
func proc(function: Int = f2()) { function; function; function }
proc() // still outputs one "hello"
func proc(function: Int = f2()) { function() } // π compilation error: not a function
func f1() { print("hello") }
var f2 = f1
func proc(function: () = f2()) {
print(function)
}
proc()
So, here (function: () = f2()) first evaluates f2() as a call, which prints hello and then assigns the value Void OR () to the parameter function; then prints (), right?
And this just prints hello...
func f1() { print("hello") }
var f2 = f1
func proc(function: ()->() = f2) {
function()
}
proc()
When unfamiliar with something I find it helpful to consider a different less confusing example:
() -> () // π€
(String) -> Int // π‘
e.g. coming from a different language you may assume that f and f() are the same (IIRC some languages allow omitting empty brackets and still call a function), but you won't assume that f and f(parameter) is the same (as parameter is obviously required).
print(foo())
print(foo) // π€ I came from language X, does this still call a function in Swift?
print(bar("hello"))
print(bar) // π‘I came from language X, but this can't possibly call a function with a parameter in Swift
// unless that parameter has a default value, but let's not complicate things at this point.
There are a few potentially confusing points to Swift newcomers in this area:
In here:
() -> ()
"Void" could be used to substitute the second "()" but not the first
While you can omit "-> Void" or, equally "-> ()" when declaring a function:
func foo() -> Void {}
func foo() -> () {} // the same
func foo() {} // the same
you can't do it when declaring a type:
var x: () -> Void
var y: () // not the same!
Uniquely to () it could mean both the type and the value (there is nothing else like this in Swift):
var y: () = ()
var x: ((), ()) = ((), ())
Tuples have similar syntax as function parameters.
On top of everything you could enclose expression in () without changing of their meaning.
0
(0) // same
((0)) // same
If we could go back and time we could've change swift to at least not use () as a substitute for Void and void constants. Too late now.
Some highly confusing declarations for you (valid Swift):
var x: () -> () -> () -> ()
var y: ((()), ((()))) -> ((())) -> ((())) -> (((())))
x is a function that, when called, returns another function, that in turn returns another function. x is () -> () -> () -> Void; x() is () -> () -> Void; x()() is () -> Void.
y has a lot more parentheses than it needs, and is really (Void, Void) -> () -> () -> Void. This is a chained function in the same way that x is, but the first call has to be y((),()) rather than just y().