# Improve nested functions' visibility or order-dependency

**URL:** <https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935>\
**Category:** Pitches\
**Created:** [February 19, 2020, 5:28pm UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935 "2020-02-19T17:28:32Z")\
**Posts on this page:** 18\
**Page:** 2

<div class="post-metadata">

**Author:** ![CTMacUser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/ctmacuser/32/1802_2.png) [@CTMacUser](https://forums.swift.org/u/CTMacUser)\
**Post date:** [February 21, 2020, 2:26am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/21 "2020-02-21T02:26:57Z")

</div>

Yes, this is what I meant.

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [February 21, 2020, 2:31am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/22 "2020-02-21T02:31:01Z")

</div>

So, I just removed it. Still can be found in the reply's history. My brain wasn't working at the time when I posted it. It also is kind of irrelevant to the pitch anyway.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 3:33am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/23 "2020-02-21T03:33:51Z")

</div>

I will trust the ability of this forum to expand all quotes to show the related texts (and codes). If it doesn't expand, well, I will re-quote to include the code.

* * *

> [@Jens](#):
>
> (which crashes the compiler)

I'm sure we can leave out all that crash the compiler. They are bugs in some way since _compiler should never crash_.

* * *

> [@Jens](#):
>
> Although not entirely so, as we saw above:

This is very consistent with the model. You declared a closure, then immediately call it. It would quickly translate to

```swift
func foo() {
    func _unnamed() {
        bar()
    }
    _unnamed()
    if Bool.random() { return }
    func bar() {
        print("bar")
    }
}
foo()

```

which compiles (and runs, printing bar).

* * *

> [@Jens](#):
>
> Note that this compiles:
> 
> ```swift
> func foo() {
> func bar() {
> incrementCount()
> }
> var count = 0
> func incrementCount() {
> count += 1
> print(count)
> }
> }
> 
> ```

It doesn't compile on my machine... 🤔 because `bar`

```swift
Cannot capture 'incrementCount', which would use 'count' before it is declared.

```

Xcode 11.3.1 (11C504) btw.

* * *

> [@Jens](#):
>
> Since this compiles (and prints bar):

Type declarations seem to be much safer than function declaration, and so have much more lenient positioning. You can't meaningfully capture local variable anyway.

```swift
func foo() {
    let a = 9
    S.bar()
    return
    struct S {
        static func bar() {
            print(a)
        }
    }
}

```

This doesn't compile, because

```swift
Struct declaration cannot close over value 'a' defined in outer scope

```

* * *

I remember a discussion somewhere in this forum that function capturing must happen at call site, not declaration site. So all relevant variables must be declared before the call site. Every example here seems to support that model.

Another rule is already mentioned by @SwiftUI that a function must be declared before it can be called, which makes sense to me.

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [February 21, 2020, 6:01am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/24 "2020-02-21T06:01:52Z")

</div>

> [@Lantua](#):
>
> I'm sure we can leave out all that crash the compiler. They are bugs in some way since _compiler should never crash_ .

I don't see what you mean here. Of course the crash is caused by a compiler bug, that's (part of) why I filed the [bug report](https://bugs.swift.org/browse/SR-12243). We cannot "leave out all that crashes the compiler". The crashing example is interesting because it's not obvious if it's intended to compile or result in a compile time error. (And both the compiler crash and the compile time error talking about a "variable" `bar` instead of function `bar`, might possibly be indicating that there are more bugs and inconsistencies in the compiler related to the ordering of nested functions.)

> [@Lantua](#):
>
> This is very consistent with the model. You declared a closure, then immediately call it. It would quickly translate to

I don't get this either. Again, I think you're ignoring the greater question (and demonstrated inconsistency) and focus on explaining an obvious detail. Of course I know that I'm using an immediately invoked closure expression, and that it could _very roughly_ be translated to a function declaration followed by a call to that function. The _important_ thing here though, is that it demonstrated that `bar()` was **declared after it was called** (via the immediately invoked closure expression).

> [@Lantua](#):
>
> a function must be declared before it can be called, which makes sense to me.

So, would you say that the function `bar` is "declared _before_ it is called" here:

```swift
// This program compiles and runs, printing bar:
func foo() {
    {
        bar()
    }() // <--- bar is called here (via the immediately invoked closure expr)
    if true {
        return
    }
    func bar() { // <--- bar is declared here
        print("bar")
    }
}
foo()

```

?

It's not only declared _after_ it's called, it's even declared after the outer function `foo` returns, at a place in the code where no _statement_ will be evaluated. And note that I'm _not_ saying that this shouldn't compile. I think it should, as it currently does. What I'm saying is that the other two examples in the [bug report](https://bugs.swift.org/browse/SR-12243) should compile too.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 6:36am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/25 "2020-02-21T06:36:26Z")

</div>

> [@Jens](#):
>
> The crashing example is interesting because it's not obvious if it's intended to compile or result in a compile time error.

Perhaps we talked past each other here. We can use any example when we start designing, but one that crashes the compiler is not useful for when we're still figuring out what the compiler is doing. From what I've read so far, we seem to be on that phase–figuring out the current rules. I take it that way because you said

> [@Jens](#):
>
> then why shouldn't this

as if the compiler already rejects it. I pointed out that it didn't reject the code. It was just confused (and perhaps so was I 😛 ).

> [@Jens](#):
>
> Again, I think you're ignoring the greater question (and demonstrated inconsistency) and focus on explaining an obvious detail.

I'm saying that closure doesn't add anything to the table. We can just talk about function declaration/usage inside a function. No use in confusing ourself further. Most discussion will apply almost trivially to closures (or the other way around) anyway.

> [@Jens](#):
>
> What I'm saying is that the other two examples in the [bug report](https://bugs.swift.org/browse/SR-12243) should compile too.

I agree.

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 6:40am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/26 "2020-02-21T06:40:55Z")

</div>

> [@Jens](#):
>
> The _important_ thing here though, is that it demonstrated that `bar()` was **declared after it was called** (via the immediately invoked closure expression).

That's an important question, and not obvious one to spot from the example (with all the closure shenanigan).

In so far, I gathered that there are 2 scopes, the current scope, and the inner scope.

The current scope is at the same level as the function declaration. The inner scope is all that is inside any function declaration.

Using function in the current scope requires that you call if after declaration, while inner scope can use any functions in the current scope (which is outer scope from inner scope perspective). There's an extra rule that, at call site, all that needs to be captured are initialized (one of you example managed to violate this rule, but I couldn't compile it on any of my machines).

So that's why

```swift
func foo() {
    func _unnamed() {
        bar() <-- inner scope, can use any function
    }
    _unnamed() <-- current scope, can use only foo
    if true {
        return
    }
    func bar() {
        print("bar") <-- inner scope
    }
}

```

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [February 21, 2020, 6:42am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/27 "2020-02-21T06:42:00Z")

</div>

> [@Lantua](#):
>
> From what I've read so far, we seem to be on that phase–figuring out the current rules.

Well, I think that there are clearly some inconsistencies in the compiler: Either all three examples of the [bug report](https://bugs.swift.org/browse/SR-12243) should compile, or none of them should compile. Currently, one compiles, one crashes compiler and one results in a compile time error.

> [@Jens](#):
>
> > What I'm saying is that the other two examples in the [bug report](https://bugs.swift.org/browse/SR-12243) should compile too.
> 
> I agree.

OK, fine, that's not the impression I got earlier : )

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 6:46am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/28 "2020-02-21T06:46:50Z")

</div>

> [@Jens](#):
>
> OK

To be clear, I think case A and B should do the same thing, whether to accept or reject it. Perhaps case C too as one quickly have A and B as the work around.

Though I'm not sure how we can find a consistent rule that in turn accept it with as much leniency as the current design.

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [February 21, 2020, 6:48am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/29 "2020-02-21T06:48:17Z")

</div>

> [@Lantua](#):
>
> ![](https://global.discourse-cdn.com/swift/original/2X/c/ca7d2c272a947983e1685cece28b269de49424b0.png) Jens:
> 
> > Note that this compiles:
> > 
> > ```swift
> > func foo() {
> > func bar() {
> > incrementCount()
> > }
> > var count = 0
> > func incrementCount() {
> > count += 1
> > print(count)
> > }
> > }
> > 
> > ```
> 
> It doesn't compile on my machine... 🤔 because `bar`
> 
> ```swift
> Cannot capture 'incrementCount', which would use 'count' before it is declared.
> 
> ```
> 
> Xcode 11.3.1 (11C504) btw.

I didn't test it yesterday, and assumed it would compile. Just tested it now, and it didn't compile for me either. I'm using the same Xcode version. What's your IDE @Jens ?

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 6:50am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/30 "2020-02-21T06:50:11Z")

</div>

IIRC, part of the reason nested function works the way it is, is that it must support 2 things,

- capturing
- recursion

It was the same discussion I mentioned earlier. If only I could find it...

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [February 21, 2020, 6:51am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/31 "2020-02-21T06:51:29Z")

</div>

> [@Lantua](#):
>
> Using function in the current scope requires that you call if after declaration, while inner scope can use any functions in the current scope (which is outer scope from inner scope perspective). There's an extra rule that, at call site, all that needs to be captured are initialized (one of you example managed to violate this rule, but I couldn't compile it on any of my machines).

I've not managed to violate that rule as far as I know. And I have not questioned it, I've merely demonstrated that it exists. It's the other (imho) inconsistencies that I've pointed out, but I've already done that as clear as I possibly can in the [bug report](https://bugs.swift.org/browse/SR-12243), and I don't think further speculation will lead anywhere, I prefer to wait for somebody who _knows_ the intended rules to explain them.

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [February 21, 2020, 6:59am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/32 "2020-02-21T06:59:33Z")

</div>

Ah, that compiles only with a recent snapshot (I happened to have that toolchain selected in Xcode without thinking about it at the time) .

That is:

```swift
// This program compiles with dev snapshot 2020-02-16,
// but not with eg the default toolchain of Xcode 11.3.1 (11C504):
func foo() {
    func bar() {
        incrementCount()
    }
    // bar() // <--- Uncomment and it will not compile with dev snapshot either. 
    var count = 0
    func incrementCount() {
        count += 1
        print(count)
    }
}
foo()

```

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [February 21, 2020, 7:00am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/33 "2020-02-21T07:00:52Z")

</div>

> [@Jens](#):
>
> I prefer to wait for somebody who _knows_ the intended rules to explain them

This thread would definitely greatly benefit from some compiler people's opinions. As far as the conversations have gone, we are still not certain of the rationales behind the current design. Maybe someone from the core team could chime in?

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 7:05am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/34 "2020-02-21T07:05:10Z")

</div>

Found it. About the reason why closures (functions) capture variables at call site.

> [@Why is the \`{}\` syntax called \`closure expression\` in swift?](https://forums.swift.org/t/why-is-the-syntax-called-closure-expression-in-swift/30198/10):
>
> It's a bit splitting hairs, but no closure record is formed by the compiler until a call site is seen. While this can be seen as merely an optimization for local functions in isolation, it's really necessary for it to work this way for mutually-recursive local functions to work practically with the reference counting and strict initialization semantics Swift requires. If you have: func outer(x: inout T) { var y = 0 func foo() { print(x) bar() } func bar() { print(y) foo(…

---

<div class="post-metadata">

**Author:** ![Jens](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jens/32/12903_2.png) [@Jens](https://forums.swift.org/u/Jens)\
**Post date:** [February 21, 2020, 7:10am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/35 "2020-02-21T07:10:16Z")

</div>

Yes, but as far as I can see, the main question of this thread is not answered by that, or maybe I'm missing something?

Again, all that I'm really wondering about is succinctly expressed in the [bug report](https://bugs.swift.org/browse/SR-12243), and it doesn't involve any capturing.

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [February 21, 2020, 7:17am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/36 "2020-02-21T07:17:36Z")

</div>

This makes sense. In a way, what is needed is to extend this declaration-at-call-site feature to all members in a function I guess? For example:

```swift
func foo() {
    let x = bar()
    func bar() -> Int { return 1 }
}

```

In the example above, if both `x` and `bar` are declared at call site, then the problem would be solved?

However, why is the nested function case so special? If it were a struct/class/enum/protocol, this wouldn't be a problem:

```swift
struct Foo {
    static let x = bar()
    static func bar() -> Int { return 1 }
}

```

Furthermore, the declaration-at-call-site feature seems to have gone much further, so long as it's not within a function. For example, the following code compiles, but will have runtime error:

```swift
struct Foo {
    static let a: Int = b
    static let b: Int = a
    static func printA() { print(a) }
}
Foo.printA()
```

---

<div class="post-metadata">

**Author:** ![Lantua](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/lantua/32/8868_2.png) [@Lantua](https://forums.swift.org/u/Lantua)\
**Post date:** [February 21, 2020, 7:43am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/37 "2020-02-21T07:43:52Z")

</div>

> [@Jens](#):
>
> I can see, the main question of this thread is not answered by that, or maybe I'm missing something?

Right, I’m still running in my own head.

The real constraint is that call site is after all captured variables. Right now that constraint are cleverly split into two rules:

- Function declaration is beneath capture list.
- Call site is beneath function declaration.

Which does explain the how C violates the rule, and how A side steps it by calling `bar` from the inner scope instead of current scope. The thread seems to be partially about getting rid of the second rule.

> [@wowbagger](#):
>
> In the example above, if both `x` and `bar` are declared at call site, then the problem would be solved?

I believe that is one way the rule can be relaxed. If we remove the second rule (from above), and replace it with

- Call site is beneath all captured list.

It’s probably a workable setup. Though that may also complicate the rule set.

> [@wowbagger](#):
>
> If it were a struct/class/enum/protocol, this wouldn't be a problem:

They can’t capture anything anyway. It’s probably safe to put it anywhere.

> [@wowbagger](#):
>
> For example, the following code compiles, but will have runtime error:

Funny that. Mine’s full of compile errors about using `a` and `b` before `self`.

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [February 21, 2020, 7:48am UTC](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935/38 "2020-02-21T07:48:11Z")

</div>

> [@Lantua](#):
>
> ![](https://global.discourse-cdn.com/swift/original/2X/f/ff2238b7a895861805224383027c31baa550fe94.jpeg) wowbagger:
> 
> > For example, the following code compiles, but will have runtime error:
> 
> Funny that. Mine’s full of compile errors about using `a` before `self` is initialized, and vice versa.

Oops... my bad. `a` and `b` are supposed to be static. Fixed it now.

[Previous page](https://forums.swift.org/t/improve-nested-functions-visibility-or-order-dependency/33935.md?page=1)
