Name of variable of function type as parameter type of other functions, instead of definition?

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).

Thanks
Neerav

Can you post some code snippets that illustrate this problem?

Make sure to use a code block (triple backquotes) so that the code is easy to read.

Share and Enjoy

Quinn β€œThe Eskimo!” @ DTS @ Apple

Yep, an example of what you want would make your question clearer.

I guess you are asking (to simplify) why do we need to write ": Bool" type declaration explicitly below:

func proc(v: Bool = true) {...}

instead of just:

func proc(v = true) {...}

although I am not sure I've interpreted your question right.

You have not interpreted my question right, yet, you might have solved my query. Allow me to explain...

I think the reason we need to write...

func proc(function: ()->void) { /*do something*/}

instead of

func f1() { /*do something*/ }
var f2 = f1
func proc(function: f2) { /*do something*/ }

is that the parameter function in proc sould be able to accept any function of the type () -> void and not just f1 ??

That brings us to the question, can we write (a function type as default parameter)...

func f1() { print("hello f1") }
var f2 = f1
func proc(function: () =  f2()) {function}

this didn't print anything in the playground console!

You probably want this:

func f1() { print("hello f1") }
var f2 = f1
func proc1(function: () -> Void = f1) { function() }
func proc2(function: () -> Void = f2) { function() }

Note, you still can't write just:

func proc1(function = f1) { function() }

for the same reason you can't omit ": Bool" in my example (whatever that reason is).

I forgot to make a call to proc()
Now, its working fine.

So basically we want the function as a default parameter and it works!

here's the code...

func f1() { print("hello f1") }
var f2 = f1
func proc(function: () = f2()) {function}
proc()

output..
hello f1

It works but not the way you think it does :-)

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()

Output...

function as default parameter

Yes!

Note that when you have "()" as a parameter type (instead of a proper "() -> Void") you can't pass a variable of a function type:

func proc(function: () = f2) // πŸ›‘ compilation error

which hints you to correct mistake:

func proc(function: () -> Void = f2) // βœ…

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.

I retested this and its working fine...

func f1() { print("hello") }
var f2 = f1
func proc(function:  () =  f2()) {
    function
}
proc()

Output
hello

You can check it in playgrounds...
Screenshot 2023-09-28 at 6.29.14 PM

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
proc(f2) // πŸ›‘ compilation error, not an Int
1 Like

Got it!

I tried this and what you said was right...

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()

Right.

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:

  1. In here:
() -> ()

"Void" could be used to substitute the second "()" but not the first

  1. 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!
  1. Uniquely to () it could mean both the type and the value (there is nothing else like this in Swift):
var y: () = ()
var x: ((), ()) = ((), ())
  1. Tuples have similar syntax as function parameters.

  2. 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: ((()), ((()))) -> ((())) -> ((())) -> (((())))
1 Like

var x: () -> () -> () -> ()
var y: ((()), ((()))) -> ((())) -> ((())) -> (((())))

Can tou explain this please? :slight_smile:

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().