I come from a mainframe background so some of the newer concepts (newer to me) are at times hard to grasp; therefore, can someone explain to me in laymans terms what the difference is between a function and a closure and why I would ever want to use a closure over a function?
Closures vs. Functions
Roughly, a closure is a block of code that may capture variable values from its surrounding scope.
Roughly, a function is a statically defined block of code that may use variable values from its surrounding scope.
Note that these are almost exactly the same thing, at least at a conceptual level. The difference is that functions are traditionally invoked in the scope where they are defined, whereas closures are invoked — potentially — far away from their point of definition. That's why functions use, but closures capture, the relevant parts of their surrounding environment. A closure is similar to a C-style callback, except that instead of needing a separate "context" parameter, it has its own context built in.
In Swift, a function (including a method) is semantically just a closure with a static name — you can pass a function name anywhere that a closure parameter is required, assuming that the type signature is correct. The compiler takes care of smoothing over the difference between "use" and "capture".
Are closures defined at the same level as functions or are they defined globally ?
functions can be defined globally, closures can not be.
Here is a little write up to help take from: https://www.weheartswift.com/closures/
Functions are a special kind of closures. There are three kinds of closures:
- global functions – they have a name and cannot capture any values
- nested functions – they have a name and can capture values from their enclosing functions
- closure expressions – they don’t have a name and can capture values from their context
A Swift function is a closure, and a closure is a typed value. The type of a closure is written like this:
(parameter-tuple) -> return-value
There are variables of closure type — including function declarations — and there are literals of closure type — what you would think of as a function body between braces.
The following are the same thing in Swift:
func A (x: Int) -> Bool { return x > 0 }
let A: (Int) -> Bool = { x in return x > 0 } // or ...
let A = { (x: Int) in return x > 0 } // ... because the compiler can infer the full closure type
The Swift guide explains this pretty well:
The description in weheartswift is pretty much stolen from the Apple Swift docs. (Look at them side by side and you'll see.) But you have to be a bit careful in either case, because they're an introductory explanation, not a technical description.
The Apple version is more correct: a function is a special case of a closure, not a special kind of closure. They're all closures of the same "kind", because they can be used interchangeably. What's different about the function "case" is that functions have a slightly different declaration syntax.
Note that "global functions" and "nested functions" don't really mean global functions and nested functions, since that leaves out methods (functions defined within classes or structs). It really means "functions not nested in a closure/function scope" and "functions nested in a closure/function scope", but that's a bit of a mouthful for introductory material.
Lastly, closures can be defined globally, if that's understood to mean closure variables (as in the examples I posted earlier). If you're taking it to mean closure literals, they can certainly be used globally (as on the RHS of those examples).
if they are the same thing, where do the second definition go, as I get NO REDEFINITION ERROR ?
let foo = { (n: Int) -> Int in return 2*n + 1 }
print(foo(5)) // 11
func foo(n: Int) -> Int {
return 2*n-1
}
print(foo(5)) // 11
It turns out they're not the same thing, in terms of the way declaration syntax works in Swift. However, that's not the answer to your question, and I'll come back to that.
To the compiler, declaring a function or method is different from declaring a closure variable. That's because there is extra stuff related to argument names that applies only to functions. For that reason, it doesn't surprise me that declaring a function 'foo' doesn't conflict with declaring a variable 'foo'.
OTOH, using a function or closure name can be ambiguous. Something like your 'foo(5)' could refer to:
Module.foo // a global variable of closure type in current module "Module"
self.foo // an instance method in the current class
foo // invocation of a closure variable in the current scope
It looks like Swift doesn't complain about ambiguity when the current context fails to distinguish between these possible interpretations. This seems like a bug or defect.
I get NO REDEFINITION ERROR ?
How are you testing this? Top-level code in Swift tends to be more forgiving about variable redeclaration than code within functions. So, for example, if I take your code and put it inside a function like this:
func wrapper() {
… your code here …
}
the compiler (Xcode 7.3.1) complains about the redeclaration of
foo
. Given that you rarely write top-level code, the lack of an error in that case is not such a big deal.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
I was testing some code in a playground (XCode 7.3.1). I understand that it is not a working situation, but semantics are there too.
I get NO REDEFINITION ERROR and I definitely not understand why. Do the two 'foo' names live in different namespaces ?
Moreover, please, something along this that shows I still need to clarify.
Independently of any context, is there any small difference in writing :
var a = 10
let foo = { (n: Int) -> Int in 2*n+a }
instead of :
var a = 10
func foo(n: Int) -> Int {
return 2*n+a
}
Is the keyword func only something like a macro which expands into a closure construction ? They both seem to capture the lexical context. Or does 'func' do anything special ? May we get rid of 'func', is it only syntactic sugar ? (OK maybe a problem for recursive definitions, you may introduce something like 'myself' for auto-calling a closure ?)...
Thanks for your answer.
The difference is that a function has argument names that are part of the function signature, but a closure does not. (A closure has parameters, placed inside the braces, but the names are purely local to the closure scope.)
When you write a function call, you must use the correct argument names. When you write a closure invocation, you don't use argument names at the call site. (This isn't enforced consistently now, but is being changed in an upcoming version of Swift.)
Whether you regard this as syntactic sugar or a semantic requirement is up to you.
Another way of looking at this is that the name of your function foo is not 'foo' but 'foo(n:)'. This justifies the difference between that and parameterless function 'foo()' and variable 'foo'. The names don't conflict.
Thanks a lot. Great explanation, should be more in evidence in Apple docs.