[swift-evolution] Make nested functions less order-dependent.

Hoon H. drawtree at gmail.com
Sun Jan 15 11:45:32 CST 2017


I like to suggest relaxing ordering restriction of nested functions. In short, just allow nested functions to be defined below its call site. ("Use of local variable ‘b’ before its declaration.” error)

Here’s more explanation.

In Swift, we can define nested functions.

    func a() {
        func b() {
        }
        func c() {
        }
    }

It’s quiet flexible, so we actually can call functions regardless order of their declaration.

    func a() {
        func b() {
            c() // Calling `c` which is defined below is allowed.
        }
        func c() {
        }
    }

This is possible because `c` does not have any order-sensitive dependency.

But unfortunately, calling `b` before its declaration is not allowed. Although it has no dependency.

    func a() {
        b() // Use of local variable ‘b’ before its declaration.
        func b() {
            c()
        }
        func c() {
        }
    }

It doesn’t make sense to me that `b` is disallowed while `c` is allowed. It’d be nice if this restriction goes away. Because that allows me to do some code “outlining” layout. Please consider this sample.
    
    func work1() {
        // Illustrates big outlines first...
        bigStep1()
        bigStep2()

        func bigStep1() {
            sharedSmallStep1()
            sharedSmallStep2()
        }
        func bigStep2() {
            sharedSmallStep2()
            sharedSmallStep3()
        }

        // Describe details later...
        func sharedSmallStep1() {
            // Complex and long code...
        }
        func sharedSmallStep2() {
            // Complex and long code...
        }
        func sharedSmallStep3() {
            // Complex and long code...
        }
    }

Of course you can do this in reverse order, but in that case, we have to read them backward — from bottom to top. It’s easier to read if larger outline if on top.

I can do this with (1) un-nested free functions, or (2) enum/class/struct member functions. But this is still better because nested functions provides lexical scopes which can reduce amount of code greatly.

    func a(_ v1: Int) { // `v1` is available to all nested scopes.
        print(v1)
        b(333)
        func b(_ v2: Int) { // `v2` is available to all nested scopes.
            print(v1 + v2)
            c(555)
            func c(_ v3: Int) { // `v3` is available to all nested scopes.
                print(v1 + v2 + v3)
            }
        }
    }

In the above example, `b` and `c` automatically captures `v1`, so we don’t need to pass these values here and there. If `c` was a free function, it should have three arguments. Also, this capture does not introduce any extra order-dependency.

— Hoon H.







More information about the swift-evolution mailing list