2
2
.
.
5
5
.
.
7
7
C
C
l
l
o
o
s
s
u
u
r
r
e
e
v
v
s
s
F
F
u
u
n
n
c
c
t
t
i
i
o
o
n
n
I
I
n
n
f
f
o
o
Functions are not the same as Closures. Main differences are listed in the below table.
You can think of a Function as a wrapper around the Closure that gives you the ability to have named Parameters.
But when you assign Function to a Constant or Variable you lose this ability. Because Constant or Variable only knows that
it points to a Closure of specified Signature and Closures don't have named Parameters (as illustrated by below example).
In the below example
Function declaration is highlighted in Red
Three different types of Closure declarations are highlighted in Green
First Closure declaration specifies Data Types of Closure Input Parameters and therefore can only be stored in a
Constant or Variable that excepts Closure with 2 Input Parameters of these specific Data Types
Other two Closure declarations don't specify Data Types of Closure Input Parameters and therefore can be stored
in any Constant or Variable that excepts Closure with 2 Input Parameters (regardless of their Data Types)
From the below example we can see that Function declaration can be easily transformed into Closure declaration by
moving opening curly bracket "{" before the Signature and inserting Keyword "in" in its place.
Function declaration has its Signature outside of the curly brackets () -> () { ... }
Closure declaration is completely contained inside the curly brackets { () -> () in ... }
Functions are used
when their code needs to be executed from multiple places in the Code (to avoid Code duplication)
do declare struct and class Methods (since Functions provide additional functionality like overriding)
Closures are used as a more convenient replacement for Functions where the code needs to be called only ones.
Closures also have shorter Syntax so for these two reasons they are mostly used to define callback handlers as Function
Parameter (handler is called when asynchronous Function wants to return the result or to inform that it is finished).
All Closures can be replaced with Functions, but not all Functions can be replaced with Closures.
Functions vs Closures
SYNTAX
FUNCTION
CLOSURE
Name
You must specify Name
You can't specify Name
Parameter Names
You can have named Parameters
You can't have named Parameters
Parameter Data Types
You must specify Parameter Data Types
You can specify Parameter Data Types
Functions vs Closures
//DECLARE VARIABLES (THAT CAN HOLD CLOSURE OF SPECIFIED SIGNATURE).
let closureVariable : (String, Int) -> (String)
let functionVariable : (String, Int) -> (String)
//DECLARE FUNCTION.
func myFunction (name:String, age:Int) -> (String) { return("\(name) is \(age) years old") }
//ASSIGN FUNCTION & CLOSURES TO VARIABLES.
closureVariable = { (name:String, age:Int) -> (String) in return("\(name) is \(age) years old") }
closureVariable = { (name , age ) -> (String) in return("\(name) is \(age) years old") }
closureVariable = { (name , age ) in return("\(name) is \(age) years old") }
closureVariable = { name , age in return("\(name) is \(age) years old") }
functionVariable = myFunction //Function is converted into Closure.
//CALL FUNCTION DIRECTLY & THROUGH VARIABLE. CALL CLOSURES.
let result1 = closureVariable ("John", 20) //Can't use named Parameters.
let result2 = functionVariable("John", 20) //Can't use named Parameters anymore.
let result3 = myFunction (name:"John", age:20) //Can use named Parameters.
//DISPLAY RESULTS.
print(result1)
print(result2)
print(result3)
D
D
i
i
f
f
f
f
e
e
r
r
e
e
n
n
t
t
S
S
y
y
n
n
t
t
a
a
x
x
Functions & Closures behave exactly the same and have the exact same purpose only difference being a Syntax
To declare a Function you have to use keyword func.
There is no keyword for declaring Closure.
Function must have a name which is specified after keyword func
Closure can be without name or you can store Closure into Variable to give it a name
Syntax for defining Input Parameters is different
Function can have named Input Parameters for when Function is being called
Closure can't have named Input Parameters for when Closure is being called
Parameter names are part of Function signature
Closure only defines Parameter Data Types (there are no names)
Based on the above observations you can think of Functions as special kind of Closures that can have
name
named Parameters
Closures were invented as an afterthought to make it easier to give Function as Input Parameter to other Function.
Usually to provide completion handler for asynchronous calls. Unfortunately once introduces into Swift Closures didn't
replace Functions probably because of backward compatibility or historical reasons.
R
R
e
e
f
f
e
e
r
r
e
e
n
n
c
c
e
e
D
D
a
a
t
t
a
a
T
T
y
y
p
p
e
e
s
s
Both Functions and Closures are Reference Data Types.
This means that when you assign Function or Closure to a Variable you are storing a reference to that Function or Closure.
This means that multiple Variables will point to the same Function or Closure acting as Aliases.
By being a Reference Data Types results in some strange behaviour (strange until you understand what is going on).
Closures don't capture state. Instead Closures keep the Scope alive.
Think of Closure as a medical instrument with tubes (references) attached to a Scope keeping that Scope alive.
Here by Scope we mean Function Instance - memory allocated to store Function Parameters and nested Functions.
When Function is called, new Function Instance is created where Function Parameters are stored.
In normal circumstances when Function returns, this Instance is removed from the memory because these Input
Parameters will not be used any more by anyone else so there is no point to continue to allocate memory for them.
But this is not the case if Function returns Function/Closure. Since Closures are Reference Data Type, Outer Function only
returns a reference to Inner function. This means that this Inner Function still needs to exist somewhere in memory
otherwise Reference will point to an empty space. And if this Inner Function references Input Parameters of Outer
Function then these too still need to be kept alive somewhere in the memory or Inner Function will not be able to use
them. This all leads to a strange behaviour that when outer Function returns, its Scope/Instance is not destroyed -
Instance of Outer Function continues to leave with all its Input Parameters and Inner Function still alive.
Every time Outer Function is called, new Function Instance is created with new memory allocated for Input Parameters
and Inner Function. You can think that behind the scenes new struct Instance is actually created where
struct has Properties for storing Outer Function Input Parameters
struct has Inner Function with only its Input Parameters, and this Inner Function references Outer Function Input
Parameters by referencing these struct Properties where these Parameters are actually stored
Variable References Inner Function which references Outer Function's Input Parameter base & Local Variable counter
INNER
FUNCTION
base = 10
counter
OUTER FUNCTION INSTANCE 1
INNER
FUNCTION
base = 20
counter
OUTER FUNCTION INSTANCE 2
VARIABLE 1
VARIABLE 2
11
12
13
21
22
23
input parameter
local variable
input parameter
local variable
E
E
x
x
a
a
m
m
p
p
l
l
e
e
-
-
F
F
o
o
r
r
e
e
v
v
e
e
r
r
y
y
c
c
a
a
l
l
l
l
,
,
n
n
e
e
w
w
F
F
u
u
n
n
c
c
t
t
i
i
o
o
n
n
I
I
n
n
s
s
t
t
a
a
n
n
c
c
e
e
i
i
s
s
c
c
r
r
e
e
a
a
t
t
e
e
d
d
In this example we create a Function that Returns Reference to Inner Function as highlighted in Red.
Outer Function has base Input Parameter and counter Inner Variable.
Returned Function has no Input Parameters but it is still able to work with both base & counter Variables which it
references from inside its Body because of which they are still kept in memory after Outer Function returns.
Every time Outer Function is called, new Function Instance is created where base, counter & Inner Function are saved.
Returning Reference to Inner Function
//FUNCTION THAT RETURNS REFERENCE TO INNER FUNCTION.
func outerFunc (base: Int) -> ( () -> () ) {
var counter = 0
func innerFuncIncrement () -> () {
counter = counter + 1
print(base + counter)
}
return innerFuncIncrement
}
//NEW FUNCTION INSTANCE IS CREATED FOR outerFunc()
//STORE REFERENCE TO Inner Function
var increment10 : () -> () = outerFunc(base: 10)
increment10()
increment10()
increment10()
//NEW FUNCTION INSTANCE IS CREATED FOR outerFunc() WITH NEW counter & Inner Function
//STORE REFERENCE TO Inner Function
var increment20 : () -> () = outerFunc(base: 20)
increment20()
increment20()
increment20()
Output
11
12
13
21
22
23
E
E
x
x
a
a
m
m
p
p
l
l
e
e
-
-
S
S
t
t
r
r
u
u
c
c
t
t
I
I
n
n
s
s
t
t
a
a
n
n
c
c
e
e
f
f
o
o
r
r
e
e
v
v
e
e
r
r
y
y
F
F
u
u
n
n
c
c
t
t
i
i
o
o
n
n
I
I
n
n
s
s
t
t
a
a
n
n
c
c
e
e
We can imagine that what was discussed so far is actually implemented using structs so in this example we will rewrite
previous code by using struct and Inner Function instead of using Outer and Inner Functions.
Every time we declare an Outer Function Swift creates a struct with the same name
with Properties for storing Outer Function Input Parameters
with Inner Function that only has its own Input Parameters
Then every time Outer Function is called, Swift creates an Instance of this struct to represent Outer Function instance
Swift stores Outer Function Input Parameters into struct Properties
keeps the struct Instance alive even after the Outer Function returns so that Variable can have Reference to struct's
Inner Function (the same as when you store reference to normal struct's Function into a Variable)
Using struct and Inner Function instead of Outer and Inner Functions
class OuterFunc {
//INPUT PARAMETERS.
var base : Int
//LOCAL VARIABLES.
var counter : Int = 0
//INNER FUNCTION.
func innerFunc () -> () {
counter = counter + 1
print(base + counter)
}
//INITIALIZER.
init(base: Int) {
self.base = base
}
}
//NEW CLASS/FUNCTION INSTANCE.
var outerFunc10 : OuterFunc = OuterFunc(base: 10) //Create Instance of a Class/Outer Function
var increment10 : () -> () = outerFunc10.innerFunc //Get Reference to Inner Function
increment10()
increment10()
increment10()
//NEW CLASS/FUNCTION INSTANCE.
var outerFunc20 : OuterFunc = OuterFunc(base: 20) //Create Instance of a Class/Outer Function
var increment20 : () -> () = outerFunc20.innerFunc //Get Reference to Inner Function
increment20()
increment20()
increment20()
Output
11
12
13
21
22
23
C
C
o
o
n
n
v
v
e
e
r
r
t
t
F
F
u
u
n
n
c
c
t
t
i
i
o
o
n
n
s
s
t
t
o
o
C
C
l
l
o
o
s
s
u
u
r
r
e
e
s
s
This example shows how would it be possible to create Class that uses Closures instead of Functions if Closure Syntax
would adopt named Parameters from Function Syntax var init : (name: String, id: Int) -> () { ... }.
With Functions
//DECLARE PARENT CLASS.
class Person {
//PROPERTIES.
var name = ""
//METHODS.
func getName () -> (String) { return(name) }
func greet () -> (String) { return("My name is \(name)") }
//INITIALIZER
init(name: String) {
self.name = name
}
}
//DECLARE CHILD CLASS.
class Soldier : Person {
//NEW PROPERTIES.
var id : Int //Add new Property.
//NEW METHODS.
override func greet () -> (String) { //Override inherited Method.
var greet = super.greet() //Call Parent Method.
return("\(greet). My number is \(id).")
}
//INITIALIZER
init(name: String, id: Int) {
self.id = id
super.init(name: name)
}
}
//ACCESS PARENT FIELDS AND METHODS.
var john = Soldier(name: "John", id: 123) //Create Object from Class Soldier.
var name = john.name
var id = john.id
var greet = john.greet()
print(greet)
Output
My name is John.
My number is 123.
Currently we can't override Stored Property (which is how Closures are used in below example) but
this can be changed in future Syntax or
we can even use Computed Property which can be overridden to make it work with current Syntax
Also Closures can't reference Class Properties name and id.
With Closures instead of Functions
//DECLARE PARENT CLASS.
class Person {
//PROPERTIES.
var name = ""
//METHODS.
var getName : () -> (String) = { return(name) }
var greet : () -> (String) = { return("My name is \(name)") }
//INITIALIZER
var init : (name: String) -> () {
self.name = name
}
}
//DECLARE CHILD CLASS.
class Soldier : Person {
//NEW PROPERTIES.
var id : Int //Add new Property.
//NEW METHODS.
override var greet : () -> (String) = { //Override inherited Method.
var greet = super.greet() //Call Parent Method.
return("\(greet). My number is \(id).")
}
//INITIALIZER
var init : (name: String, id: Int) -> () {
self.id = id
super.init(name: name)
}
}
//ACCESS PARENT FIELDS AND METHODS.
var john = Soldier(name: "John", id: 123) //Create Object from Class Soldier.
var name = john.name
var id = john.id
var greet = john.greet()
print(greet)
Errors
cannot use instance member 'name' within property initialize
In this version of the example we show how to implemented greet as Computed Property so that it can be overridden.
Computed Property returns Closure since we want to be able to use it as function super.greet() and greet().
By removing override var greet Parent's greet is called (exactly as overridden Methods should behave).
Computed Property returns Closure
//DECLARE PARENT CLASS.
class Person {
//PROPERTIES.
var name = ""
//METHODS.
func getName () -> (String) { return(name) }
var greet : () -> (String) {
var greetClosure : () -> (String) = { return("My name is John.") }
return( greetClosure )
}
//INITIALIZER
init(name: String) {
self.name = name
}
}
//DECLARE CHILD CLASS.
class Soldier : Person {
//NEW PROPERTIES.
var id : Int //Add new Property.
//NEW METHODS.
override var greet : () -> (String) { //Override greet
var greet = super.greet()
var greetClosure : () -> (String) = { return("\(greet) My number is 123") }
return( greetClosure )
}
//INITIALIZER
init(name: String, id: Int) {
self.id = id
super.init(name: name)
}
}
//ACCESS PARENT FIELDS AND METHODS.
var john = Soldier(name: "John", id: 123) //Create Object from Class Soldier.
var name = john.name
var id = john.id
var greet = john.greet()
print(greet)