There is a similar pitch from 2017, but it was only about nested functions calling each other.
Currently in Swift, this is allowed:
func parentFunction() {
// localFunction1() can call localFunction2()
// even though the latter is declared later.
func localFunction1() {
localFunction2()
}
func localFunction2() {
localFunction1()
}
}
However, the following is not allowed:
var outsideVariable: Int = 0
func parentFunction() {
// Both assignments below don't compile.
// Compiler complains about localFunction3()
// being called before it's declared.
outsideVariable = localFunction3()
let localConstant: Int = localFunction3()
func localFunction3() -> Int {
return 1
}
}
The behaviour in the 2nd example is inconsistent with that in the 1st, and with all non-nested functions. What are the reasons behind this discrepancy between function visibilities? If there are no reasons behind it, I suggest that we should remove order-dependency between nested functions.
On a possibly related note, if the 2nd example is first written in the allowed order and compiled, Xcode wouldn't complain about it until it tries to compile the code the second time. I'm not sure if this is IDE-specific.
I've always interpreted this as the local function (in function scope) being a variable that hasn't been declared yet. restated, localFunction(1|2|3) really are just closures. This makes some sense since they won't need names outside of the function. My COMPLETELY UNINFORMED guess is that changing this would involve giving them names that somehow reflected that they are nested within the method. That seems non-trivial. It would also open the door for exposing type aliases specific to functions which is something that I've wanted for a while.
I haven't thought of it in this way, that nested functions being unnamed closures. However, although it might explain my 2nd example, according to my incomplete understanding of closures, the functions in the 1st example shouldn't be able to capture each other if they were unnamed closures?
^ By this, do you mean type aliases for function types? e.g.
typealias (NonDecimal) -> BinaryLogic = (Int) -> Bool
// Compiler infers that NonDecimal is a type alias for Int,
// and BinaryLogic is a type alias for Bool.
My best guess for why the first example works is that nothing in scope is calling them so there isn't any real ambiguity about initialization order. Neither localFunction is ever really materialized. If you modify the first example and call localFunction(1|2) before their declaration, you get the same diagnostic. In this way, I don't think that the first snippet is terribly relevant to the second. You are completely able to capture a strongly named closure that will be declared later. You still can't call it before it has been defined.
Just to clarify, functions, nested and otherwise, are very much named. Arguably, they have stronger name binding than closures. A name for them is given and guaranteed at the point of definition unlike a closure.
Stated another way, functions are closures with at least one guaranteed name
func foo() {
func bar() { // ERROR: Closure captures 'count' before it is declared
incrementCount()
}
bar()
var count = 0
func incrementCount() {
count += 1
print(count)
}
}
And a bit less on topic maybe:
// This compiles and prints Cool:
func foo() {
print(String("\(T.self)".map({ $0 == "B" ? "C" : $0 })))
return
typealias T = Bool // WARNING: Code after 'return' will never be executed
}
foo()
I'm going to respond to each of your examples separately, each in their own comment.
I didn't sleep much last night, and it hinders my ability to think a bit. So I'm testing each example in Xcode, instead of completely reasoning everything out mentally. Basically what I am doing is that I keep all the nested functions as functions (I only consider 1 layer of nesting so far), and transform the nesting function (the outmost layer) into a struct/class/enum, and its nested local properties as private static properties for the struct/class/enum, then I see if the code works in a not-nested-functions case. The reasoning is that all the properties local to a function behave much like private static properties to the function "type" they live in.
struct Foo {
incrementCount() // Compiler complains the following:
// Expected '{' in body of function declaration
// Expected 'func' keyword in instance method declaration
// Compiler suggests inserting "func"
private static var count = 0 // Hmm ...
private static func incrementCount() {
count += 1
print(count)
}
}
In regards to the function example: This will not compile, because incrementCount() tries to access count before it's declared. In this case, the order is important, because both incrementCount() and var count = 0 change the state of the function.
In regards to the struct I modeled after the function: After testing a few similar designs, I found that the compiler will not allow a function that alters its context's state to be called from within that context. In other words, the struct Foo will not be able to call incrementCount() from anywhere within Foo that's sibling to incrementCount(). incrementCount() is only callable from outside of Foo like Foo. incrementCount(), if it's not private.
UPDATE 1
I removed update 1, because it wasn't relevant and could detract people from the goal of this pitch.
UPDATE 2
This is for the same reason. bar() calls incrementCount(), which accesses count, but bar() is called before count is declared. In this case like the previous one, the order between calling bar() and declaring count matters, but the order between declaring bar() and declaring count doesn't matter.
I think this in a general sense is on topic. I haven't read any bit of the compiler's code, but I guess the ordering of things should be relevant across different context, if we expect a consistent behaviour in the language.
And yes I think this should compile, too. Since Swift doesn't allow redeclaration of type aliases, it should allow all type aliases' declaration to be orderless.
Yes that's the current state of Swift syntax. The question is, why should it be like this and what purpose does it serve?
The current behaviours in functions is inconsistent with those in structs, classes, and enums. If functions are types and first class citizens in Swift, then I think it should be treated as such syntactically and behaviourally, unless a break from the consistency is necessary.
Interesting, looks like closure/anonymous func has better context awareness than pure func, or indirect func call is much flexible than direct func call.
So weird, need some compiler guru to explain it.
Your copy/paste from the function to the structure is completely nonsensical. Functions run statements and declarations, but structures (and classes and enumerations) only use declarations. The function call within a structure definition is a statement, which canβt be done. The compiler tried telling you by thinking you just didnβt finish writing a function definition, but you missed it.
If this is the case, then yes I agree with you that it's a statement, and structures don't allow statements within its definition. I think this is what you refer to, but I can't be completely sure, since the above code snippet doesn't contain any