I know there are several related question and moreover I can find many posts in the Internet.
However, I can't understand the fact that closures can hold references. In case of a reference type, it is totally usual and very reasonable, but how about a value type, including struct and enum?
See this code.
let counter: () -> Int
var count = 0
do {
counter = {
count += 1
return count
}
}
count += 1 // 1
counter() // 2
counter() // 3
We can access the value type count through two ways. One is by using count directly and the another is through the closure counter.
However, if we write
let a = 0
let b = a
, in the memory b has of course a different area with a because they are value type. And this behavior is a distinct feature of value type which is different with reference type.
And then backing to the closure topic, closure has the reference to value type's variable or constant.
So, can I say the value type's feature that we can't have any references to value type is changed in case of closure's capturing values?
To me, capturing references to value type is very surprising and at the same time the experience I showed above indicates that.
Could you explain this thing?
I think the confusion is by thinking too hard about value types vs reference types. This has very little to do with that. Let's make number be reference types:
class RefInt: CustomStringConvertible {
let value: Int
init(value: Int) { self.value = value }
var description: String { return "\(value)" }
}
let counter: () -> RefInt
var count = RefInt(value: 0)
do {
counter = {
count = RefInt(value: count.value + 1)
return count
}
}
count = RefInt(value: count.value + 1) // 1
counter() // 2
counter() // 3
Does this feel different in any way? I hope not. It's the same thing, just in references. This isn't a value/reference thing.
The point is that, as you note, the closure captures the variable. Not the value of the variable, or the value of the reference the variable points to, but the variable itself). So changes to the variable inside the closure are seen in all other places that have captured that variable (including the caller). This is discussed a bit more fully in Capturing Values.
A bit deeper if you're interested (now I'm getting into a bit of technicalities that may be beyond what you care about right now):
Closures actually have a reference to the variable, and changes they make immediately occur, including calling didSet, etc. This is not the same as inout parameters, which assign the value to their original context only when they return. You can see that this way:
let counter: () -> Int
var count = 0 {
didSet { print("set count") }
}
do {
counter = {
count += 1
print("incremented count")
return count
}
}
func increaseCount(count: inout Int) {
count += 1
print("increased Count")
}
print("1")
count += 1 // 1
print("2")
counter() // 2
print("3")
counter() // 3
increaseCount(count: &count)
This prints:
1
set count
2
set count
incremented count
3
set count
incremented count
increased Count
set count
Note how "set count" is always before "incremented count" but is after "increased count." This drives home that closures really are referring to the same variable (not value or reference; variable) that they captured, and why we call it "capturing" for closures, as opposed to "passing" to functions. (You can also "pass" to closures of course, in which case they behave exactly like functions on those parameters.)
Related
I'm learning F# and get stuck with the concept of mutable keyword.
Please see the below example:
let count =
let mutable a = 1
fun () -> a <- a + 1; a
val count: unit -> int
Which increases by 1 every time it's called with (). But next code does not:
let count =
let mutable a = 1
a <- a + 1
a
val count: int
Which is always 2.
In the book I'm studying with, it says with the first example, "The initialization of mutable value a is done only once, when the function has called first time."
When I started learning FP with haskell, the way it handled side effects like this totally burnt my brain, but F# mutable is destroying my brain again, with a different way. What's the difference between above two snippets? And, what's the true meaning and condition of above sentence, about the initialization of mutable value?
Your second example
let count =
let mutable a = 1
a <- a + 1
a
Defines a mutable variable initialised to 1, then assigns a new value (a + 1) to it using the <- operator before returning the updated value on the last line. Since a has type int and this is returned from the function the return type of the function is also int.
The first example
let count =
let mutable a = 1
fun () -> a <- a + 1; a
also declares an int a initialised to 1. However instead of returning it directly it returns a function which closes over a. Each time this function is called, a is incremented and the updated value returned. It could be equivalently written as:
let count =
let mutable a = 1
let update () =
a <- a + 1
a
update
fun () -> ... defines a lambda expression. This version returns a 1-argument function reflected in the different return type of unit -> int.
The first example of count initializes a mutable variable, and returns a closure around this variable. Every time you call that closure, the variable is increased, and its new value returned.
The second example of count is just an initialization block that sets the variable, increases it once, and returns its value. Referring to count again only returns the already computed value again.
Can some one please explain to me how it works
var count: Int?
count = 1
if let count = count {
//do something.
}
Why there is no compiler error at if let count = count as we already created a variable named count as var count: Int?. How come two variables with same name possible?
Swift treated as both variables as a different one. The "count" that declared first can be treated as global one while the constant "count" is only available inside if condition, so it can't access outside if condition.
Optional Variable: It can contain a value or a Nil value. Nil represents the absence of a value or nothing
var count: Int? // Optional Variable
Here variable count is global variable.
Optional Binding: It is the way by which we try to retrieve a values from a chain of optional variable.
if let count = count {
//do something.
}
Here constant count value is available only with in the scope. It cannot be accessed outside the scope.
This is called optional binding
if let constantName = someOptional {
statements
}
someOptional is checked to see if it's nil or has data. If it's nil, the if-statement just doesn't get executed. If there's data, the data gets unwrapped and assigned to constantName for the scope of the if-statement. Then the code inside the braces is executed.
I have a problem with a closure that is meant to be created and then being executed within another function over the range of the 2D pixel raster of an image where it shall basically called like this:
filter(i,j) and return a value based on its arguments.
I thought this code should work but it complains that the closure variable I have created is not initialized. I guess that means that I did not gave it arguments, but I wont within this function as the data is known to the closure at the time when it interacts with the image. How can I setup a closure which does not care about initialization?
Thank you in advance :)
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var closure:(i:Int, j:Int)->Int
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
closure = filter
}
//other if statements with different closure definitions follow...
//This call throws error: variable used before being initialized
let image = filterImage(closure)
}
You use the variable closure before the compiler is certain that it is initialized. You can solve this in 2 ways, depending on what you need:
Add an else-clause to your if and set closure to a default closure.
Make closure optional by defining it as var closure: ((i: Int, j: Int) -> Int)? and then you can check if it is optional before using it by using closure?(i, j) or if let filter = closure { filter(i, j)}.
Also, try to use better variable names such as filterClosure. closure on its own doesn't really say much.
The problem is that you define your closure as:
var closure:(i:Int, j:Int)->Int
Then you initialize it only if you enter the if
If not, that var is not initialized, hence the compiler warning
Possible solution:
func processFilter(type:FilterType){
var x = 0
var y = 0
//create cloure
var filterClosure:((i:Int, j:Int)->Int)?
if(type == FilterType.MyFilter) {
x = 1024
y = 2048
func filter(i:Int, j:Int)->Int {
return i*j*x*y*4096
}
//compiler does not complain here...
filterClosure = filter
}
//other if statements with different closure definitions follow...
if let closure = filterClosure {
let image = filterImage(closure)
}
}
Your closure is only initialized if the code enters your if block (i.e. if type == FilterType.MyFilter). In the other case it is left uninitialized.
Today I was just going through some basic swift concepts and was working with some examples to understand those concepts. Right now I have completed studying tuples.
I have got one doubt i.e, what is the need of using tuples ? Ya I did some digging on this here is what I got :
We can be able to return multiple values from a function. Ok but we can also do this by returning an array.
Array ok but we can return an multiple values of different types. Ok cool but this can also be done by array of AnyObject like this :
func calculateStatistics (scores:[Int])->[AnyObject]
{
var min = scores[0]
var max = scores[0]
var sum = 0
for score in scores
{
if score > max{
max = score
}
else if score < min{
min = score
}
sum += score
}
return [min,max,"Hello"]
}
let statistics = calculateStatistics([25,39,78,66,74,80])
var min = statistics[0]
var max = statistics[1]
var msg = statistics[2] // Contains hello
We can name the objects present in the tuples. Ok but I can use a dictionary of AnyObject.
I am not saying that Why to use tuples when we have got this . But there should be something only tuple can be able to do or its easy to do it only with tuples. Moreover the people who created swift wouldn't have involved tuples in swift if there wasn't a good reason. So there should have been some good reason for them to involve it.
So guys please let me know if there's any specific cases where tuples are the best bet.
Thanks in advance.
Tuples are anonymous structs that can be used in many ways, and one of them is to make returning multiple values from a function much easier.
The advantages of using a tuple instead of an array are:
multiple types can be stored in a tuple, whereas in an array you are restricted to one type only (unless you use [AnyObject])
fixed number of values: you cannot pass less or more parameters than expected, whereas in an array you can put any number of arguments
strongly typed: if parameters of different types are passed in the wrong positions, the compiler will detect that, whereas using an array that won't happen
refactoring: if the number of parameters, or their type, change, the compiler will produce a relevant compilation error, whereas with arrays that will pass unnoticed
named: it's possible to associate a name with each parameter
assignment is easier and more flexible - for example, the return value can be assigned to a tuple:
let tuple = functionReturningTuple()
or all parameters can be automatically extracted and assigned to variables
let (param1, param2, param3) = functionReturningTuple()
and it's possible to ignore some values
let (param1, _, _) = functionReturningTuple()
similarity with function parameters: when a function is called, the parameters you pass are actually a tuple. Example:
// SWIFT 2
func doSomething(number: Int, text: String) {
println("\(number): \(text)")
}
doSomething(1, "one")
// SWIFT 3
func doSomething(number: Int, text: String) {
print("\(number): \(text)")
}
doSomething(number: 1, text: "one")
(Deprecated in Swift 2) The function can also be invoked as:
let params = (1, "one")
doSomething(params)
This list is probably not exhaustive, but I think there's enough to make you favor tuples to arrays for returning multiple values
For example, consider this simple example:
enum MyType {
case A, B, C
}
func foo() -> (MyType, Int, String) {
// ...
return (.B, 42, "bar")
}
let (type, amount, desc) = foo()
Using Array, to get the same result, you have to do this:
func foo() -> [Any] {
// ...
return [MyType.B, 42, "bar"]
}
let result = foo()
let type = result[0] as MyType, amount = result[1] as Int, desc = result[2] as String
Tuple is much simpler and safer, isn't it?
Tuple is a datastructure which is lighter weight than heterogeneous Array. Though they're very similar, in accessing the elements by index, the advantage is tuples can be constructed very easily in Swift. And the intention to introduce/interpolate this(Tuple) data structure is Multiple return types. Returning multiple data from the 'callee' with minimal effort, that's the advantage of having Tuples. Hope this helps!
A tuple is ideally used to return multiple named data from a function for temporary use. If the scope of the tuple is persistent across a program you might want to model that data structure as a class or struct.
These two snippets produced the same result. What is numberOfTimes (method?) How do you implement numberOfTimes?
class Counter
{
var count: Int = 0
func incrementBy(amount: Int, numberOfTimes times: Int)
{
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, numberOfTimes: 7)
class Counter
{
var count: Int = 0
func incrementBy(amount: Int, times: Int)
{
count += amount * times
}
}
var counter = Counter()
counter.incrementBy(2, times: 7)
numberOfTimes is not a method, it is an external parameter name. Times is an internal parameter name. Check out this reference for more information.
I'm not sure I understand the question correctly, but numberOfTimes is the external parameter name for the times argument.
The only difference is that in one case you have to call the method as
counter.incrementBy(2, numberOfTimes: 7)
whereas if you leave it out, the local name is automatically used also as external
counter.incrementBy(2, times: 7)
More on the subject in the official docs.
That's an external parameter name, and it identifies the name you use when calling the function, whereas the local parameter name (times in your code) is how is the parameter is referenced from within the function.
Read more about Function Parameter Names