Search code examples
iosobjective-cxcodeswiftswift-playground

Swift closure strange behaviour


Why does this code compile (in Playground):

func text (f: String -> Void) {
    f("text")
}

func foo(s: String) {
    countElements(s)
}

text() {
    s in
        foo(s)
}

And this one doesn't:

func text (f: String -> Void) {
    f("text")
}

func foo(s: String) {
    countElements(s)
}

text() {
    s in
        countElements(s)
}

With error message:

Cannot convert the expression's type '(($T3) -> ($T3) -> $T2) -> (($T3) -> $T2) -> $T2'       to type '_BuiltinIntegerLiteralConvertible'

I can tell that there is something with return type, kinda Swift thinks that I want to return int but I just want to print it


Solution

  • The second version of the code works if you add an explicit return statement:

    text() {
        s in countElements(s)
        return
    }
    

    The reason for that to happens is that it uses implicit return, being a single statement closure, so it tries uses the return value of countElements, which doesn't match with the expected return type, Void. The explicit return fixes that.

    As to why it behaves in a different way, in the former case foo implicitly returns Void, which matches the closure return type.

    More info: Implicit Returns from Single-Expression Closures